#include "trader.h"
#include "ctp.h"

InvestorInfo::InvestorInfo(UserInfo* parent) : tagCTPInvestorInfo{0}, parent(parent)
{

}

AccountInfo::AccountInfo(UserInfo* parent) : tagCTPAccountInfo{ 0 }, parent(parent)
{

}

void PositionInfo::update()
{
	if (!hcode) {
		HZQDB hs[3] = { 0 };
		ZQDBGetCodeByTradeCode(g_ctp_module, sp->InstrumentID, hs, 3);
		hcode = hs[0];
	}
	zqdb::CodeT<CTPCODEINFO> code(hcode);
	strcpy(this->Broker, sp->BrokerID);
	strcpy(this->Investor, sp->InvestorID);
	strcpy(this->User, parent->User);
	strcpy(this->Exchange, sp->ExchangeID);
	strcpy(this->Code, sp->InstrumentID);
	this->Currency = CURRENCY_CNY;
	this->Price = sp->Position > 0 ? sp->PositionCost / sp->Position / code->VolumeMultiple: 0;
	this->Volume = sp->Position;
	this->YVolume = sp->YdPosition;
	if (sp->PosiDirection == THOST_FTDC_PD_Long) {
		this->FrozenVolume = sp->ShortFrozen;
	}
	else {
		this->FrozenVolume = sp->LongFrozen;
	}
	this->Direction = PDIRECTION_CTP2VT(sp->PosiDirection);
	this->Profit = sp->CloseProfit + sp->PositionProfit;

	tagPositionInfo* info = this;
	this->h = TDMgr::Inst().update_position(this->h, info);
}

void OrderInfo::update()
{
	if (!hcode) {
		HZQDB hs[3] = { 0 };
		ZQDBGetCodeByTradeCode(g_ctp_module, sp->InstrumentID, hs, 3);
		hcode = hs[0];
	}
	strcpy(this->Broker, sp->BrokerID);
	strcpy(this->Investor, sp->InvestorID);
	strcpy(this->User, parent->User);
	strcpy(this->Order, sp->id);
	strcpy(this->Exchange, sp->ExchangeID);
	strcpy(this->Code, sp->InstrumentID);
	this->InsertTime = CTPTime2Time(sp->InsertTime);
	if (sp->OrderStatus == THOST_FTDC_OST_Canceled) {
		this->UpdateTime = CTPTime2Time(sp->CancelTime);
	}
	else {
		this->UpdateTime = CTPTime2Time(sp->UpdateTime);
	}
	this->Currency = CURRENCY_CNY;
	this->Price = sp->LimitPrice;
	this->Volume = sp->VolumeTotalOriginal;
	this->LeaveVolume = sp->VolumeTotal;
	this->Direction = DIRECTION_CTP2VT(sp->Direction);
	this->Offset = OFFSET_CTP2VT(sp->CombOffsetFlag[0]); //开平标志 OFFSET_OPEN
	this->Type = ORDERTYPE_CTP2VT(sp->OrderPriceType, sp->TimeCondition, sp->VolumeCondition); //订单类型 ORDER_LIMIT
	this->Status = STATUS_CTP2VT(sp->OrderStatus); //订单状态 ORDER_STATUS_SUBMITTING
	tagOrderInfo* info = this;
	this->h = TDMgr::Inst().update_order(this->h, info);
	//LOG4T(this->User, "order %s status:%s", this->Order, gbk_to_utf8(sp->StatusMsg));
}

void TradeInfo::update()
{
	if (!hcode) {
		HZQDB hs[3] = { 0 };
		ZQDBGetCodeByTradeCode(g_ctp_module, sp->InstrumentID, hs, 3);
		hcode = hs[0];
	}
	strcpy(this->Broker, sp->BrokerID);
	strcpy(this->Investor, sp->InvestorID);
	strcpy(this->User, parent->User);
	strcpy(this->Order, sp->OrderSysID);
	strcpy(this->Trade, sp->id);
	strcpy(this->Exchange, sp->ExchangeID);
	strcpy(this->Code, sp->InstrumentID);
	this->TradeTime = CTPTime2Time(sp->TradeTime);
	this->Currency = CURRENCY_CNY;
	this->Price = sp->Price;
	this->Volume = sp->Volume;
	this->Direction = DIRECTION_CTP2VT(sp->Direction);
	this->Offset = OFFSET_CTP2VT(sp->OffsetFlag); //开平标志 OFFSET_OPEN

	tagTradeInfo* info = this;
	this->h = TDMgr::Inst().update_trade(this->h, info);
}

UserInfo::UserInfo() :tagCTPUserInfo{ 0 }, investor(std::make_shared<InvestorInfo>(this)), account(std::make_shared<AccountInfo>(this))
{

}

void UserInfo::clear()
{
	h = nullptr;
	investor->h = nullptr;
	account->h = nullptr;
	long_positions.clear();
	short_positions.clear();
	orders.clear();
	trades.clear();
}

void UserInfo::update_investor(const CThostFtdcInvestorField& ctp_investor)
{
	strcpy(investor->Broker, ctp_investor.BrokerID);
	strcpy(investor->User, this->User);
	strcpy(investor->Investor, ctp_investor.InvestorID);
	strcpy(investor->InvestorName, ctp_investor.InvestorName);
	strcpy(investor->InvestorGroupID, ctp_investor.InvestorGroupID);
	investor->IdentifiedCardType = ctp_investor.IdentifiedCardType;
	strcpy(investor->IdentifiedCardNo, ctp_investor.IdentifiedCardNo);
	investor->IsActive = ctp_investor.IsActive;
	strcpy(investor->Telephone, ctp_investor.Telephone);
	strcpy(investor->Address, ctp_investor.Address);
	strcpy(investor->OpenDate, ctp_investor.OpenDate);
	strcpy(investor->Mobile, ctp_investor.Mobile);
	strcpy(investor->CommModelID, ctp_investor.CommModelID);
	strcpy(investor->MarginModelID, ctp_investor.MarginModelID);
	investor->h = TDMgr::Inst().update_investor(investor->h, investor.get());
}

void UserInfo::update_account(std::shared_ptr<CTPAccountInfo> sp)
{
	strcpy(account->Broker, sp->BrokerID);
	strcpy(account->User, this->User);
	strcpy(account->Account, sp->AccountID);
	///上次质押金额
	account->PreMortgage = sp->PreMortgage;
	///上次信用额度
	account->PreCredit = sp->PreCredit;
	///上次存款额
	account->PreDeposit = sp->PreDeposit;
	///上次结算准备金
	account->PreBalance = sp->PreBalance;
	///上次占用的保证金
	account->PreMargin = sp->PreMargin;
	///利息基数
	account->InterestBase = sp->InterestBase;
	///利息收入
	account->Interest = sp->Interest;
	///入金金额
	account->Deposit = sp->Deposit;
	///出金金额
	account->Withdraw = sp->Withdraw;
	///冻结的保证金
	account->FrozenMargin = sp->FrozenMargin;
	///冻结的资金
	account->FrozenCash = sp->FrozenCash;
	///冻结的手续费
	account->FrozenCommission = sp->FrozenCommission;
	///当前保证金总额
	account->CurrMargin = sp->CurrMargin;
	///资金差额
	account->CashIn = sp->CashIn;
	///手续费
	account->Commission = sp->Commission;
	///平仓盈亏
	account->CloseProfit = sp->CloseProfit;
	///持仓盈亏
	account->PositionProfit = sp->PositionProfit;
	///期货结算准备金
	account->Balance = sp->Balance;
	///可用资金
	account->Available = sp->Available;
	///可取资金
	account->WithdrawQuota = sp->WithdrawQuota;
	///基本准备金
	account->Reserve = sp->Reserve;
	///交易日
	strncpy(account->TradingDay, sp->TradingDay, 8);
	///结算编号
	account->SettlementID = sp->SettlementID;
	///信用额度
	account->Credit = sp->Credit;
	///质押金额
	account->Mortgage = sp->Mortgage;
	///交易所保证金
	account->ExchangeMargin = sp->ExchangeMargin;
	///投资者交割保证金
	account->DeliveryMargin = sp->DeliveryMargin;
	///交易所交割保证金
	account->ExchangeDeliveryMargin = sp->ExchangeDeliveryMargin;
	///保底期货结算准备金
	account->ReserveBalance = sp->ReserveBalance;
	///币种代码
	strncpy(account->CurrencyID, sp->CurrencyID, 3);
	///上次货币质入金额
	account->PreFundMortgageIn = sp->PreFundMortgageIn;
	///上次货币质出金额
	account->PreFundMortgageOut = sp->PreFundMortgageOut;
	///货币质入金额
	account->FundMortgageIn = sp->FundMortgageIn;
	///货币质出金额
	account->FundMortgageOut = sp->FundMortgageOut;
	///货币质押余额
	account->FundMortgageAvailable = sp->FundMortgageAvailable;
	///可质押货币金额
	account->MortgageableFund = sp->MortgageableFund;
	///特殊产品占用保证金
	account->SpecProductMargin = sp->SpecProductMargin;
	///特殊产品冻结保证金
	account->SpecProductFrozenMargin = sp->SpecProductFrozenMargin;
	///特殊产品手续费
	account->SpecProductCommission = sp->SpecProductCommission;
	///特殊产品冻结手续费
	account->SpecProductFrozenCommission = sp->SpecProductFrozenCommission;
	///特殊产品持仓盈亏
	account->SpecProductPositionProfit = sp->SpecProductPositionProfit;
	///特殊产品平仓盈亏
	account->SpecProductCloseProfit = sp->SpecProductCloseProfit;
	///根据持仓盈亏算法计算的特殊产品持仓盈亏
	account->SpecProductPositionProfitByAlg = sp->SpecProductPositionProfitByAlg;
	///特殊产品交易所保证金
	account->SpecProductExchangeMargin = sp->SpecProductExchangeMargin;
	///业务类型
	account->BizType = sp->BizType;
	///延时换汇冻结金额
	account->FrozenSwap = sp->FrozenSwap;
	///剩余换汇额度
	account->RemainSwap = sp->RemainSwap;
	account->h = TDMgr::Inst().update_account(account->h, account.get());
}

std::shared_ptr<PositionInfo> UserInfo::update_position(std::shared_ptr<CTPPositionInfo> sp)
{
	if (sp->is_short()) {
		auto it = short_positions.find(sp->id);
		if (it != short_positions.end()) {
			auto& position = it->second;
			position->sp = sp;
			position->update();
			return position;
		}
		else {
			auto position = std::make_shared<PositionInfo>();
			position->parent = this;
			position->sp = sp;
			position->update();
			short_positions[position->Code] = position;
			return position;
		}
	}
	else {
		auto it = long_positions.find(sp->id);
		if (it != long_positions.end()) {
			auto& position = it->second;
			position->sp = sp;
			position->update();
			return position;
		}
		else {
			auto position = std::make_shared<PositionInfo>();
			position->parent = this;
			position->sp = sp;
			position->update();
			long_positions[position->Code] = position;
			return position;
		}
	}
}

std::shared_ptr<OrderInfo> UserInfo::update_order(std::shared_ptr<CTPOrderInfo> sp)
{
	auto it = orders.find(sp->id);
	if (it != orders.end()) {
		auto& order = it->second;
		order->sp = sp;
		order->update();
		return order;
	}
	else {
		auto order = std::make_shared<OrderInfo>();
		order->parent = this;
		order->sp = sp;
		order->update();
		orders[order->Order] = order;
		return order;
	}
}

std::shared_ptr<TradeInfo> UserInfo::update_trade(std::shared_ptr<CTPTradeInfo> sp)
{
	auto it = trades.find(sp->id);
	if (it != trades.end()) {
		auto& trade = it->second;
		trade->sp = sp;
		trade->update();
		return trade;
	}
	else {
		auto trade = std::make_shared<TradeInfo>();
		trade->parent = this;
		trade->sp = sp;
		trade->update();
		trades[trade->Trade] = trade;
		return trade;
	}
}

CTPTrader::CTPTrader(bool base_flag, boost::asio::io_service& service) : Base()
, base_flag_(base_flag)
, service_(service)
, timer_(service)
{

}

bool CTPTrader::start(char* xml, int xmlflag)
{
	CFG_FROM_XML(cfg, xml, xmlflag);

	if (!parse_userinfo(userinfo_, cfg)) {
		if (is_test()) {

		}
		else {
			LOG4E(STR_MODULE_NAME " parse userinfo failed");
			return false;
		}
	}

	user_ = std::make_shared<UserInfo>();
	strcpy(user_->Broker, userinfo_.BrokerID); //经纪公司代码
	strcpy(user_->User, userinfo_.UserID); //用户代码
	user_->Status = USER_STATUS_OFFLINE; //用户状态
	userid_ = user_->User + std::string(".") + user_->Broker;
	if (is_test()) {
		service().post(boost::bind(&This::on_test_login, shared_from_this()));
	}
	else {
		//远程登录需要考虑无效账号问题
		if (req_login_) {
			//先不创建用户
		}
		else {
			//user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
		}
		service().post(boost::bind(&This::set_online, shared_from_this()));
	}

	return true;
}

bool CTPTrader::start(zqdb::Msg& msg)
{
	req_login_ = msg;
	auto Broker = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), "");
	auto User = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), "");
	auto Password = msg.GetParam("Password", "");
	auto AuthCode = msg.GetParam("AuthCode", "");
	auto AppID = msg.GetParam("AppID", "");
	auto FrontAddress = msg.GetParam("FrontAddress", "");
	const char* str_format = R"({"BrokerID": "%s",
						"UserID" : "%s",
						"Password" : "%s",
                        "AuthCode": "%s",
                        "AppID": "%s",
						"FrontAddress" : [
							"%s"
						]})";
	char str_json[1024] = { 0 };
	sprintf(str_json, str_format, Broker
		, User
		, Password
		, AuthCode
		, AppID
		, FrontAddress
	);
	return start(str_json, XUtil::XML_FLAG_JSON_STRING);
}

void CTPTrader::update(zqdb::Msg& msg)
{
	if (is_test(ZQDB_USER_BROKER_TEST)) {
		test_date_ = msg.GetParamAsUInt("Date");
		test_time_ = msg.GetParamAsUInt("Time");
	}
}

void CTPTrader::stop()
{
	stop_flag_ = true;
	unregister_timer(); 
	if (is_test()) {
		//user_->Status = USER_STATUS_OFFLINE;
		//user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
	}
	else {
		service().post(boost::bind(&This::set_offline, shared_from_this()));
	}
}

void CTPTrader::register_timer_for_reconnect()
{
	LOG4I(STR_MODULE_NAME " %s CTPTrader::register_timer_for_reconnect", userid_.c_str());
	timer_.expires_from_now(boost::posix_time::milliseconds(60 * 1000));
	timer_.async_wait(boost::bind(&This::on_timer_for_reconnect, this, boost::asio::placeholders::error));
}

void CTPTrader::register_timer_for_requery()
{
	LOG4I(STR_MODULE_NAME " %s CTPTrader::register_timer_for_requery", userid_.c_str());
	timer_.expires_from_now(boost::posix_time::milliseconds(1000));
	timer_.async_wait(boost::bind(&This::on_timer_for_requery, this, boost::asio::placeholders::error));
}

void CTPTrader::register_timer_for_refresh()
{
	timer_.expires_from_now(boost::posix_time::milliseconds(1000));
	timer_.async_wait(boost::bind(&This::on_timer_for_refresh, this, boost::asio::placeholders::error));
}

void CTPTrader::unregister_timer()
{
	LOG4I(STR_MODULE_NAME " %s CTPTrader::unregister_timer", userid_.c_str());
	boost::system::error_code ec;
	timer_.cancel(ec);
}

//以下是当前service线程回调函数

void CTPTrader::set_online()
{
	if (is_stop()) {
		return;
	}
	ASSERT(!api_);
	LOG4I(STR_MODULE_NAME " %s connecting", userid_.c_str());
	/*if (base_flag_) {
	TDMgr::Inst().set_online(shared_from_this());
	}*/
	if (user_) {
		user_->Status = USER_STATUS_CONNECT;
		if (user_->h) {
			user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
		}
	}

	boost::filesystem::path flowpath(ZQDBGetDataDir());flowpath.append(".my");
	flowpath.append(STR_MODULE_NAME).append(userinfo_.BrokerID).append(userinfo_.UserID);
	if (!boost::filesystem::exists(flowpath))
	{
		boost::filesystem::create_directories(flowpath);
	}
	//boost::filesystem::path currentpath = boost::filesystem::current_path();
	//boost::filesystem::current_path(flowpath);
	api_ = CThostFtdcTraderApi::CreateFtdcTraderApi(flowpath.string().c_str());
	//boost::filesystem::current_path(currentpath);

	for (size_t i = 0; i<userinfo_.FrontAddress.size(); i++)
	{
		api_->RegisterFront((char*)userinfo_.FrontAddress[i].c_str());
	}
	for (size_t i = 0; i<userinfo_.NsAddress.size(); i++)
	{
		api_->RegisterNameServer((char*)userinfo_.NsAddress[i].c_str());
	}

	api_->SubscribePublicTopic(THOST_TERT_RESTART); //这样可以更新到最新的合约状态
	api_->SubscribePrivateTopic(THOST_TERT_QUICK); //交易委托、成交、持仓通过请求+推送更新到最新

	api_->RegisterSpi(this);

	// 使客户端开始与行情发布服务器建立连接
	api_->Init();
}

void CTPTrader::set_offline()
{
	LOG4I(STR_MODULE_NAME " %s %s", userid_.c_str(), u8"disconnecting");
	/*if (base_flag_) {
	TDMgr::Inst().set_offline(shared_from_this());
	}*/
	if (is_stop()) {
		if (user_) {
			user_->Status = USER_STATUS_OFFLINE;
			if (user_->h) {
				user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
			}
		}
	}

	if (api_) {
		api_->Release();
		api_ = NULL;
	}
}

int CTPTrader::request(zqdb::Msg& msg)
{
	int reqid = ZQDBStoreRequest(msg);
	service().post(boost::bind(&This::on_request, shared_from_this(), reqid));
	return ZQDB_STATUS_OK;
}

//以下是当前service线程回调函数

void CTPTrader::on_clear_new_tradingday()
{
	if (!is_stop()) {
		if (is_test()) {
			clear();
		}
		else {
			if (init_flag_) {
				if (user_) {
					user_->clear();
				}
			}
			else {
				set_offline();
				clear();
			}
		}
	}
}

void CTPTrader::on_init_new_tradingday()
{
	if (!is_stop()) {
		if (is_test()) {
			//重建用户
			if (user_) {
				user_->Status = USER_STATUS_CONNECTED;
				if (user_->h)
					user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
			}
			on_test_init();
		}
		else {
			if (init_flag_) {
				//重建用户
				if (user_) {
					user_->Status = USER_STATUS_CONNECTED;
					if (user_->h)
						user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
				}
			}
			else {
				//
			}
		}
	}
}

void CTPTrader::on_end_new_tradingday()
{
	if (is_stop()) {
		return;
	}
	if (is_test()) {
		on_test_normal();
	}
	else {
		if (init_flag_) {
			init_flag_ = false;
			on_normal();
		}
		else {
			set_offline();
			set_online();
		}
	}
}

void CTPTrader::on_request(int reqid)
{
	zqdb::Msg msg(ZQDBFindRequest(reqid));
	HNMSG rsp = nullptr;
	if (!is_stop() && IsStateful(CTP_STAT_MAX)) {
		switch (msg.GetMsgType())
		{
		case ZQDB_MSG_REQUEST_DO: {
			switch (msg.GetReqType())
			{
			case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_ORDER_INSERT: {
				int err = -1;
				CThostFtdcInputOrderField req = { 0 };
				/*size_t sz = 0;
				tagOrderInfo& data = *(tagOrderInfo*)msg.GetData(&sz);
				memcpy(req.ExchangeID, data.Exchange, sizeof(req.ExchangeID));
				memcpy(req.InstrumentID, data.Code, sizeof(req.InstrumentID));
				req.LimitPrice = data.Price;
				req.VolumeTotalOriginal = data.Volume;
				req.Direction = data.Direction;
				req.CombOffsetFlag[0] = data.Offset;
				char order_type = data.Type;*/
				com::zqdb::proto::msg::ReqOrderInsert req_order_insert;
				size_t datalen = 0;
				const char* data = msg.GetData(&datalen);
				req_order_insert.ParseFromArray(data, datalen);
				//auto code = TDMgr::Inst().code2ctp(req_order_insert.code().c_str());
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				strcpy(req.UserID, m_UserInfo.UserID);
				strcpy(req.ExchangeID, req_order_insert.exchange().c_str());
				strcpy(req.InstrumentID, req_order_insert.code().c_str());
				req.LimitPrice = req_order_insert.price();
				req.VolumeTotalOriginal = req_order_insert.volume();
				req.Direction = DIRECTION_VT2CTP(req_order_insert.direction());
				req.CombOffsetFlag[0] = OFFSET_VT2CTP(req_order_insert.offset());
				char order_type = req_order_insert.type();
				if (order_type == ORDER_FAK) {
					req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
					req.TimeCondition = THOST_FTDC_TC_IOC;
					req.VolumeCondition = THOST_FTDC_VC_AV;
				}
				else if (order_type == ORDER_FOK) {
					req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
					req.TimeCondition = THOST_FTDC_TC_IOC;
					req.VolumeCondition = THOST_FTDC_VC_CV;
				}
				else {
					req.OrderPriceType = ORDERTYPE_VT2CTP(order_type);
					req.TimeCondition = THOST_FTDC_TC_GFD;
					req.VolumeCondition = THOST_FTDC_VC_AV;
				}
				//req.OrderRef = str(self.order_ref),
				//req.InvestorID": self.userid,
				//req.UserID": self.userid,
				//req.BrokerID": self.brokerid,
				req.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
				req.ContingentCondition = THOST_FTDC_CC_Immediately;
				req.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
				req.IsAutoSuspend = 0;
				req.MinVolume = 1;
				sprintf(req.OrderRef, "%d", m_OrderRef++);
				req.RequestID = reqid;
				if (is_test()) {
					err = 0;
					service().post(boost::bind(&This::on_mock_order_insert, shared_from_this(), req));
				}
				else {
					err = api_->ReqOrderInsert(&req, req.RequestID);
				}
				if (err != 0) {
					zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
					rsp_msg.SetNode(msg.GetNode());
					rsp_msg.SetBizType(msg.GetBizType());
					rsp_msg.SetID(msg.GetID());
					rsp_msg.SetError(err, "ReqOrderInsert failed.");
					rsp = (HNMSG)rsp_msg;
					ZQDBMsgRef(rsp);
				}
			} break;
			case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_ORDER_CANCEL: {
				int err = -1;
				com::zqdb::proto::msg::ReqOrderCancel req_order_cancel;
				size_t datalen = 0;
				const char* data = msg.GetData(&datalen);
				req_order_cancel.ParseFromArray(data, datalen);
				const auto& orderid = req_order_cancel.orderid();
				auto it = orders_.find(orderid);
				if (it != orders_.end()) {
					auto order = it->second;
					CThostFtdcInputOrderActionField req = { 0 };
					strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
					strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
					strcpy(req.UserID, m_UserInfo.UserID);
					strcpy(req.InstrumentID, req_order_cancel.code().c_str());
					strcpy(req.ExchangeID, req_order_cancel.exchange().c_str());
#if 0
					strcpy(req.OrderRef, order->OrderRef);
					req.FrontID = order->FrontID;
					req.SessionID = order->SessionID;
#else
					strcpy(req.OrderSysID, orderid.c_str());
#endif
					req.ActionFlag = THOST_FTDC_AF_Delete;
					req.OrderActionRef = m_OrderRef++;
					req.RequestID = reqid;
					if (is_test()) {
						err = 0;
						service().post(boost::bind(&This::on_mock_order_cancel, shared_from_this(), req, order));
					}
					else {
						err = api_->ReqOrderAction(&req, req.RequestID);
					}
				}
				if (err != 0) {
					zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
					rsp_msg.SetNode(msg.GetNode());
					rsp_msg.SetBizType(msg.GetBizType());
					rsp_msg.SetID(msg.GetID());
					rsp_msg.SetError(err, "ReqOrderAction failed.");
					rsp = (HNMSG)rsp_msg;
					ZQDBMsgRef(rsp);
				}
			} break;
			default: {
				zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
				rsp_msg.SetNode(msg.GetNode());
				rsp_msg.SetBizType(msg.GetBizType());
				rsp_msg.SetID(msg.GetID());
				rsp_msg.SetError(-1, "unknown request...");
				rsp = (HNMSG)rsp_msg;
				ZQDBMsgRef(rsp);
			} break;
			}
		} break;
		}
	}
	else {
		zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
		rsp_msg.SetNode(msg.GetNode());
		rsp_msg.SetBizType(msg.GetBizType());
		rsp_msg.SetID(msg.GetID());
		rsp_msg.SetError(-1, "initializing...");
		rsp = (HNMSG)rsp_msg;
		ZQDBMsgRef(rsp);
	}
	if (rsp) {
		ZQDBSendMsg(rsp);
		ZQDBMsgDelete(rsp);
		ZQDBRemoveRequest(reqid);
	}
}

void CTPTrader::do_login_err_response(int err, const char* msg)
{
	zqdb::Msg rsp(ZQDB_MSG_RESPONSE);
	rsp.SetNode(req_login_.GetNode());
	rsp.SetBizType(req_login_.GetBizType());
	rsp.SetID(req_login_.GetID());
	rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), req_login_.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER)));
	rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), req_login_.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER)));
	if (err == ZQDB_STATUS_OK && is_test()) {
		rsp.SetParamAsUInt("HZQDB", (size_t)user_->h);
	}
	rsp.SetError(err, msg);
	req_login_.Reset();
	ZQDBSendMsg(rsp);
}

void CTPTrader::do_login_response(const char* msg)
{
	zqdb::Msg rsp(ZQDB_MSG_RESPONSE);
	rsp.SetNode(req_login_.GetNode());
	rsp.SetBizType(req_login_.GetBizType());
	rsp.SetID(req_login_.GetID());
	rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), req_login_.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER)));
	rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), req_login_.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER)));
	rsp.SetContinue(msg);
	ZQDBSendMsg(rsp);
}

void CTPTrader::do_err_response(int reqid, int err, const char* errmsg)
{
	zqdb::Msg msg(ZQDBFindRequest(reqid));
	if (msg) {
		zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
		rsp_msg.SetNode(msg.GetNode());
		rsp_msg.SetBizType(msg.GetBizType());
		rsp_msg.SetID(msg.GetID());
		rsp_msg.SetError(err, errmsg);
		ZQDBRemoveRequest(reqid);
		ZQDBSendMsg(rsp_msg);
	}
}

void CTPTrader::do_response(int reqid, const char* key, const char* value)
{
	zqdb::Msg msg(ZQDBFindRequest(reqid));
	if (msg) {
		zqdb::Msg rsp_msg(ZQDB_MSG_RESPONSE);
		rsp_msg.SetNode(msg.GetNode());
		rsp_msg.SetBizType(msg.GetBizType());
		rsp_msg.SetID(msg.GetID());
		rsp_msg.SetParam(key, value);
		ZQDBRemoveRequest(reqid);
		ZQDBSendMsg(rsp_msg);
	}
}

void CTPTrader::on_update(HZQDB hcode)
{
	if (is_stop()) {
		return;
	}
	zqdb::CodeT<CTPCODEINFO> code(hcode);
	if (is_test()) {
		//模拟撮合成交
		for (auto& pr : orders_)
		{
			auto& order = pr.second;
			switch (order->OrderStatus)
			{
			case THOST_FTDC_OST_PartTradedQueueing:
			case THOST_FTDC_OST_NoTradeQueueing: {
				if (stricmp(code->TradeCode, order->InstrumentID) == 0) {
					mock_match(code, order);
				}
			} break;
			}
		}
	}
	//刷新资金和持仓的动态权益
	bool update_account = false;
	//std::shared_ptr<CTPPositionInfo> long_position, short_position;
	double PositionProfitDiff = 0;
	for (auto& pr : long_positions_)
	{
		if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
			auto& position = pr.second;
			//long_position = position;
			double old_PositionProfit = position->PositionProfit;
			if (position->Position > 0) {
				double PositionCostPrice = position->PositionCost / position->Position / code->VolumeMultiple;
				position->PositionProfit = (code->Close - PositionCostPrice) * position->Position * code->VolumeMultiple;
			}
			else {
				position->PositionProfit = 0;
			}
			user_->update_position(position);
			PositionProfitDiff += position->PositionProfit - old_PositionProfit;
			update_account = true;
			break;
		}
	}
	for (auto& pr : short_positions_)
	{
		if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
			auto& position = pr.second;
			//short_position = position;
			double old_PositionProfit = position->PositionProfit;
			if (position->Position > 0) {
				double PositionCostPrice = position->PositionCost / position->Position / code->VolumeMultiple;
				position->PositionProfit = (PositionCostPrice - code->Close) * position->Position * code->VolumeMultiple;
			}
			else {
				position->PositionProfit = 0;
			}
			user_->update_position(position);
			PositionProfitDiff += position->PositionProfit - old_PositionProfit;
			update_account = true;
			break;
		}
	}
	if (update_account) {
#if 1
		account_->PositionProfit += PositionProfitDiff;
		account_->Balance += PositionProfitDiff;
#else
		//这是完全刷新方式
		account_->PositionProfit = 0;
		for (auto& pr : long_positions_)
		{
			auto& position = pr.second;
			double old_PositionProfit = position->PositionProfit;
			double PositionCostPrice = position->PositionCost / position->Position / code->VolumeMultiple;
			position->PositionProfit = (code->Close - PositionCostPrice) * position->Position * code->VolumeMultiple;
			user_->update_position(position);
			account_->PositionProfit += position->PositionProfit;
		}
		for (auto& pr : short_positions_)
		{
			auto& position = pr.second;
			double old_PositionProfit = position->PositionProfit;
			double PositionCostPrice = position->PositionCost / position->Position / code->VolumeMultiple;
			position->PositionProfit = (PositionCostPrice - code->Close) * position->Position * code->VolumeMultiple;
			user_->update_position(position);
			account_->PositionProfit += position->PositionProfit;
		}
#endif//
		user_->update_account(account_);
	}
}

void CTPTrader::on_mock_order_insert(const CThostFtdcInputOrderField& req)
{
	if (is_stop()) {
		return;
	}
	//CThostFtdcInputOrderField req = { 0 };
	CThostFtdcRspInfoField rsp_info = { 0 };
	HZQDB hs[3] = { 0 };
	ZQDBGetCodeByTradeCode(g_ctp_module, req.InstrumentID, hs, 3);
	zqdb::CodeT<CTPCODEINFO> code(hs[0]);
	if (code) {
		if (!code.IsMarketValid()) {
			rsp_info.ErrorID = 1;
			strcpy(rsp_info.ErrorMsg, "CTP:Market is invalid");
		}
		else {
			uint32_t date = 0, tradeday = 0;
			uint32_t time = code.GetNowTime(&date, &tradeday);
			if (test_date_) {
				date = test_date_;
				time = test_time_;
			}
			int volume = req.VolumeTotalOriginal;
			if (req.CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				double price = 0;
				auto order_type = ORDERTYPE_CTP2VT(req.OrderPriceType, req.TimeCondition, req.VolumeCondition);
				switch (order_type)
				{
				case ORDER_FAK:
				case ORDER_FOK:
				case ORDER_MARKET: {
					if (test_date_) {
						price = req.LimitPrice;
					} else {
						price = code->Close;
					}
				} break;
				case ORDER_LIMIT:
				default: {
					price = req.LimitPrice;
				} break;
				}
				double amount = price * volume * code->VolumeMultiple;
				double margin = req.Direction == THOST_FTDC_D_Buy ? amount * code->LongMarginRatio : amount * code->ShortMarginRatio;
				if (account_->Available < margin) {
					rsp_info.ErrorID = 1;
					strcpy(rsp_info.ErrorMsg, "可用保证金不足");
				}
			}
			else {
				std::shared_ptr<CTPPositionInfo> position;
				if (req.Direction == THOST_FTDC_D_Buy) {
					//买平，平空仓
					for (auto& pr : short_positions_)
					{
						if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
							position = pr.second;
							break;
						}
					}
				}
				else {
					//卖平，平多仓
					for (auto& pr : long_positions_)
					{
						if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
							position = pr.second;
							break;
						}
					}
				}
				if (position && volume <= position->available()) {
					//
				}
				else {
					rsp_info.ErrorID = 2;
					strcpy(rsp_info.ErrorMsg, "委托数量超出可平仓数量");
				}
			}
			if (!IsErrorRspInfo(&rsp_info)) {
				strcpy(rsp_info.ErrorMsg, "CTP:NoError");
				on_rsp_order_send(req, rsp_info, req.RequestID);
				//模拟订单撮合
				CThostFtdcOrderField order = { 0 };
				///经纪公司代码
				strcpy(order.BrokerID, req.BrokerID);
				///投资者代码
				strcpy(order.InvestorID, req.InstrumentID);
				///合约代码
				strcpy(order.InstrumentID, req.InstrumentID);
				///报单引用
				strcpy(order.OrderRef, req.OrderRef);
				///用户代码
				strcpy(order.UserID, req.UserID);
				///报单价格条件
				order.OrderPriceType = req.OrderPriceType;
				///买卖方向
				order.Direction = req.Direction;
				///组合开平标志
				memcpy(order.CombOffsetFlag, req.CombOffsetFlag, sizeof(order.CombOffsetFlag));
				///组合投机套保标志
				memcpy(order.CombHedgeFlag, req.CombHedgeFlag, sizeof(order.CombHedgeFlag));
				///价格
				order.LimitPrice = req.LimitPrice;
				///数量
				order.VolumeTotalOriginal = req.VolumeTotalOriginal;
				///有效期类型
				order.TimeCondition = req.TimeCondition;
				///GTD日期
				strcpy(order.GTDDate, req.GTDDate);
				///成交量类型
				order.VolumeCondition = req.VolumeCondition;
				///最小成交量
				order.MinVolume = req.MinVolume;
				///触发条件
				order.ContingentCondition = req.ContingentCondition;
				///止损价
				order.StopPrice = req.StopPrice;
				///强平原因
				order.ForceCloseReason = req.ForceCloseReason;
				///自动挂起标志
				order.IsAutoSuspend = req.IsAutoSuspend;
				///业务单元
				strcpy(order.BusinessUnit, req.BusinessUnit);
				///请求编号
				order.RequestID = req.RequestID;
				///本地报单编号
				strcpy(order.OrderLocalID, req.OrderRef);
				///交易所代码
				strcpy(order.ExchangeID, req.ExchangeID);
				///会员代码
				//TThostFtdcParticipantIDType	ParticipantID;
				///客户代码
				//TThostFtdcClientIDType	ClientID;
				///合约在交易所的代码
				strcpy(order.ExchangeInstID, req.InstrumentID);
				///交易所交易员代码
				//TThostFtdcTraderIDType	TraderID;
				///安装编号
				//TThostFtdcInstallIDType	InstallID;
				///报单提交状态
				order.OrderSubmitStatus = THOST_FTDC_OSS_Accepted;
				///报单提示序号
				order.NotifySequence = req.RequestID;
				///交易日
				sprintf(order.TradingDay, "%04d:%02d:%02d", XUtil::GetYear(tradeday), XUtil::GetMonth(tradeday), XUtil::GetDay(tradeday));
				///结算编号
				//strcpy(order.SettlementID, req.OrderRef);
				///报单编号
				strcpy(order.OrderSysID, req.OrderRef);
				///报单来源
				//TThostFtdcOrderSourceType	OrderSource;
				///报单状态
				order.OrderStatus = THOST_FTDC_OST_NoTradeNotQueueing;
				///报单类型
				order.OrderType = THOST_FTDC_ORDT_Normal;
				///今成交数量
				order.VolumeTraded = 0;
				///剩余数量
				order.VolumeTotal = req.VolumeTotalOriginal;
				///报单日期
				sprintf(order.InsertDate, "%04d:%02d:%02d", XUtil::GetYear(date), XUtil::GetMonth(date), XUtil::GetDay(date));
				///委托时间
				sprintf(order.InsertTime, "%02d:%02d:%02d", XUtil::GetHour(time), XUtil::GetMinute(time), XUtil::GetSecond(time));
				///激活时间
				sprintf(order.ActiveTime, "%02d:%02d:%02d", XUtil::GetHour(time), XUtil::GetMinute(time), XUtil::GetSecond(time));
				///挂起时间
				//TThostFtdcTimeType	SuspendTime;
				///最后修改时间
				sprintf(order.UpdateTime, "%02d:%02d:%02d", XUtil::GetHour(time), XUtil::GetMinute(time), XUtil::GetSecond(time));
				///撤销时间
				//TThostFtdcTimeType	CancelTime;
				///最后修改交易所交易员代码
				//TThostFtdcTraderIDType	ActiveTraderID;
				///结算会员编号
				//TThostFtdcParticipantIDType	ClearingPartID;
				///序号
				order.SequenceNo = req.RequestID;
				///前置编号
				order.FrontID = user_->FrontID;
				///会话编号
				order.SessionID = user_->SessionID;
				///用户端产品信息
				//order.UserProductInfo = user_->;
				///状态信息
				strcpy(order.StatusMsg, "");
				///用户强评标志
				order.UserForceClose = req.UserForceClose;
				///操作用户代码
				strcpy(order.ActiveUserID, req.UserID);
				///经纪公司报单编号
				order.BrokerOrderSeq = req.RequestID;
				///相关报单
				//TThostFtdcOrderSysIDType	RelativeOrderSysID;
				///郑商所成交数量
				//TThostFtdcVolumeType	ZCETotalTradedVolume;
				///互换单标志
				order.IsSwapOrder = req.IsSwapOrder;
				///营业部编号
				//strcpy(order.BranchID, req.br;
				///投资单元代码
				strcpy(order.InvestUnitID, req.InvestUnitID);
				///资金账号
				strcpy(order.AccountID, req.AccountID);
				///币种代码
				strcpy(order.CurrencyID, req.CurrencyID);
				///IP地址
				strcpy(order.IPAddress, req.IPAddress);
				///Mac地址
				strcpy(order.MacAddress, req.MacAddress);
				//先入队列
				mock_queue(code, std::make_shared<CTPOrderInfo>(order));
				//接着撮合
				mock_match(code, std::make_shared<CTPOrderInfo>(order));
			}
		}
	}
	else {
		rsp_info.ErrorID = 21;
		strcpy(rsp_info.ErrorMsg, "CTP:Can not find instrument");
	}
	if (IsErrorRspInfo(&rsp_info)) {
		on_rsp_order_send(req, rsp_info, req.RequestID);
	}
}

void CTPTrader::on_mock_order_cancel(const CThostFtdcInputOrderActionField& req, std::shared_ptr<CTPOrderInfo> order)
{
	if (is_stop()) {
		return;
	}
	switch (order->OrderStatus)
	{
	case THOST_FTDC_OST_AllTraded:
	case THOST_FTDC_OST_Canceled:
	case THOST_FTDC_OST_Unknown: {
		CThostFtdcRspInfoField rsp_info = { 0 };
		rsp_info.ErrorID = 1;
		strcpy(rsp_info.ErrorMsg, "订单不可撤销");
		on_rsp_order_cancel(req, rsp_info, req.RequestID);
		return;
	} break;
	}	
	//CThostFtdcInputOrderActionField req;
	CThostFtdcRspInfoField rsp_info = { 0 };
	HZQDB hs[3] = { 0 };
	ZQDBGetCodeByTradeCode(g_ctp_module, req.InstrumentID, hs, 3);
	zqdb::CodeT<CTPCODEINFO> code(hs[0]);
	if (code) {
		on_rsp_order_cancel(req, rsp_info, req.RequestID);
		mock_cancel(code, const_cast<std::shared_ptr<CTPOrderInfo>&>(order));
	}
	else {
		rsp_info.ErrorID = 21;
		strcpy(rsp_info.ErrorMsg, "CTP:Can not find instrument");
		on_rsp_order_cancel(req, rsp_info, req.RequestID);
	}
}

void CTPTrader::mock_update_order(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order, TThostFtdcOrderStatusType OrderStatus, TThostFtdcVolumeType VolumeTraded)
{
	uint32_t time = code.GetNowTime();///时间
	if (test_date_) {
		time = test_time_;
	}
	switch (OrderStatus)
	{
	case THOST_FTDC_OST_AllTraded: {
		order->VolumeTraded += VolumeTraded;
	} break;
	}
	///报单状态
	order->OrderStatus = OrderStatus;
	///最后修改时间
	sprintf(order->UpdateTime, "%02d:%02d:%02d", XUtil::GetHour(time), XUtil::GetMinute(time), XUtil::GetSecond(time));
	switch (OrderStatus)
	{
	case THOST_FTDC_OST_Canceled: {
		strcpy(order->CancelTime, order->UpdateTime);
	} break;
	}
	on_rtn_order(order);
}

void CTPTrader::mock_new_trade(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order
	, TThostFtdcPriceType Price, TThostFtdcVolumeType Volume)
{
	//推送成交
	CThostFtdcTradeField trade = { 0 };
	///经纪公司代码
	strcpy(trade.BrokerID, order->BrokerID);
	///投资者代码
	strcpy(trade.InvestorID, order->InvestorID);
	///合约代码
	strcpy(trade.InstrumentID, order->InstrumentID);
	///报单引用
	strcpy(trade.OrderRef, order->OrderRef);
	///用户代码
	strcpy(trade.UserID, order->UserID);
	///交易所代码
	strcpy(trade.ExchangeID, order->ExchangeID);
	///成交编号
	strcpy(trade.TradeID, order->OrderRef);
	///买卖方向
	trade.Direction = order->Direction;
	///报单编号
	strcpy(trade.OrderSysID, order->OrderSysID);
	///会员代码
	//TThostFtdcParticipantIDType	ParticipantID;
	///客户代码
	//TThostFtdcClientIDType	ClientID;
	///交易角色
	//TThostFtdcTradingRoleType	TradingRole;
	///合约在交易所的代码
	strcpy(trade.ExchangeInstID, order->ExchangeInstID);
	///开平标志
	trade.OffsetFlag = order->CombOffsetFlag[0];
	///投机套保标志
	trade.HedgeFlag = order->CombHedgeFlag[0];
	///价格
	trade.Price = Price;
	///数量
	trade.Volume = Volume;
	///成交时期
	strcpy(trade.TradeDate, order->InsertDate);
	///成交时间
	strcpy(trade.TradeTime, order->UpdateTime);
	///成交类型
	trade.TradeType = THOST_FTDC_TRDT_Common;
	///成交价来源
	//TThostFtdcPriceSourceType	PriceSource;
	///交易所交易员代码
	//TThostFtdcTraderIDType	TraderID;
	///本地报单编号
	strcpy(trade.OrderLocalID, order->OrderLocalID);
	///结算会员编号
	//TThostFtdcParticipantIDType	ClearingPartID;
	///业务单元
	strcpy(trade.BusinessUnit, order->BusinessUnit);
	///序号
	trade.SequenceNo = order->SequenceNo;
	///交易日
	strcpy(trade.TradingDay, order->TradingDay);
	///结算编号
	//TThostFtdcSettlementIDType	SettlementID;
	///经纪公司报单编号
	trade.BrokerOrderSeq = order->BrokerOrderSeq;
	///成交来源
	//TThostFtdcTradeSourceType	TradeSource;
	///投资单元代码
	//TThostFtdcInvestUnitIDType	InvestUnitID;
	//
	on_rtn_trade(std::make_shared<CTPTradeInfo>(trade));
}

void CTPTrader::mock_queue(zqdb::CodeT<CTPCODEINFO> &code, std::shared_ptr<CTPOrderInfo> &order)
{
	if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			//
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				if (test_date_) {
					price = order->LimitPrice;
				}
				else {
					price = code->Close;
				}
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->LongMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : long_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				CThostFtdcInvestorPositionField pos = { 0 };
				///合约代码
				strcpy(pos.InstrumentID, order->InstrumentID);
				///经纪公司代码
				strcpy(pos.BrokerID, order->BranchID);
				///投资者代码
				strcpy(pos.InvestorID, order->InvestorID);
				///持仓多空方向
				pos.PosiDirection = CTPDirection2PosiDirection(order->Direction);
				///投机套保标志
				pos.HedgeFlag = order->CombHedgeFlag[0];
				///持仓日期
				pos.PositionDate = THOST_FTDC_PSD_Today;
				///上日持仓
				//TThostFtdcVolumeType	YdPosition;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///今日持仓
				//pos.Position;
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				pos.LongFrozenAmount = margin;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				///开仓量
				//pos.OpenVolume;
				///开仓金额
				//pos.OpenAmount;
				//}
				///持仓成本
				//pos.PositionCost;
				///上次占用的保证金
				//TThostFtdcMoneyType	PreMargin;
				///占用的保证金
				//pos.UseMargin;
				///冻结的保证金
				//TThostFtdcMoneyType	FrozenMargin;
				///冻结的资金
				//TThostFtdcMoneyType	FrozenCash;
				///冻结的手续费
				//TThostFtdcMoneyType	FrozenCommission;
				///资金差额
				//TThostFtdcMoneyType	CashIn;
				///手续费
				//TThostFtdcMoneyType	Commission;
				///平仓盈亏
				//TThostFtdcMoneyType	CloseProfit;
				///持仓盈亏
				//TThostFtdcMoneyType	PositionProfit;
				///上次结算价
				//TThostFtdcPriceType	PreSettlementPrice;
				///本次结算价
				//TThostFtdcPriceType	SettlementPrice;
				///交易日
				strcpy(pos.TradingDay, order->TradingDay);
				///结算编号
				//TThostFtdcSettlementIDType	SettlementID;
				///开仓成本
				//pos.OpenCost;
				///交易所保证金
				//TThostFtdcMoneyType	ExchangeMargin;
				///组合成交形成的持仓
				//TThostFtdcVolumeType	CombPosition;
				///组合多头冻结
				//TThostFtdcVolumeType	CombLongFrozen;
				///组合空头冻结
				//TThostFtdcVolumeType	CombShortFrozen;
				///逐日盯市平仓盈亏
				//TThostFtdcMoneyType	CloseProfitByDate;
				///逐笔对冲平仓盈亏
				//TThostFtdcMoneyType	CloseProfitByTrade;
				///今日持仓
				//pos.TodayPosition;
				///保证金率
				//pos.MarginRateByMoney = code->LongMarginRatio;
				///保证金率(按手数)
				//TThostFtdcRatioType	MarginRateByVolume;
				///执行冻结
				//TThostFtdcVolumeType	StrikeFrozen;
				///执行冻结金额
				//TThostFtdcMoneyType	StrikeFrozenAmount;
				///放弃执行冻结
				//TThostFtdcVolumeType	AbandonFrozen;
				///交易所代码
				strcpy(pos.ExchangeID, order->ExchangeID);
				///执行冻结的昨仓
				//TThostFtdcVolumeType	YdStrikeFrozen;
				///投资单元代码
				//TThostFtdcInvestUnitIDType	InvestUnitID;
				///大商所持仓成本差值，只有大商所使用
				//TThostFtdcMoneyType	PositionCostOffset;
				///tas持仓手数
				//TThostFtdcVolumeType	TasPosition;
				///tas持仓成本
				//TThostFtdcMoneyType	TasPositionCost;
				position = std::make_shared<CTPPositionInfo>(pos);
				long_positions_[position->id] = position;
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				pos.LongFrozenAmount += margin;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
			//开多，冻结资金
			account_->FrozenMargin += margin;
			account_->Available -= margin;
			user_->update_account(account_);
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_NoTradeQueueing);
		}
		else {
			double price = 0;
			int volume = 0;
			volume = order->VolumeTotal; 
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				if (test_date_) {
					price = order->LimitPrice;
				}
				else {
					price = code->Close;
				}
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->ShortMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : short_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				CThostFtdcInvestorPositionField pos = { 0 };
				///合约代码
				strcpy(pos.InstrumentID, order->InstrumentID);
				///经纪公司代码
				strcpy(pos.BrokerID, order->BranchID);
				///投资者代码
				strcpy(pos.InvestorID, order->InvestorID);
				///持仓多空方向
				pos.PosiDirection = CTPDirection2PosiDirection(order->Direction);
				///投机套保标志
				pos.HedgeFlag = order->CombHedgeFlag[0];
				///持仓日期
				pos.PositionDate = THOST_FTDC_PSD_Today;
				///上日持仓
				//TThostFtdcVolumeType	YdPosition;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///今日持仓
				//pos.Position;
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				//pos.LongFrozenAmount = ;
				///开仓冻结金额
				pos.ShortFrozenAmount = margin;
				///开仓量
				//pos.OpenVolume;
				///开仓金额
				//pos.OpenAmount;
				//}
				///持仓成本
				//pos.PositionCost;
				///上次占用的保证金
				//TThostFtdcMoneyType	PreMargin;
				///占用的保证金
				//pos.UseMargin;
				///冻结的保证金
				//TThostFtdcMoneyType	FrozenMargin;
				///冻结的资金
				//TThostFtdcMoneyType	FrozenCash;
				///冻结的手续费
				//TThostFtdcMoneyType	FrozenCommission;
				///资金差额
				//TThostFtdcMoneyType	CashIn;
				///手续费
				//TThostFtdcMoneyType	Commission;
				///平仓盈亏
				//TThostFtdcMoneyType	CloseProfit;
				///持仓盈亏
				//TThostFtdcMoneyType	PositionProfit;
				///上次结算价
				//TThostFtdcPriceType	PreSettlementPrice;
				///本次结算价
				//TThostFtdcPriceType	SettlementPrice;
				///交易日
				strcpy(pos.TradingDay, order->TradingDay);
				///结算编号
				//TThostFtdcSettlementIDType	SettlementID;
				///开仓成本
				//pos.OpenCost;
				///交易所保证金
				//TThostFtdcMoneyType	ExchangeMargin;
				///组合成交形成的持仓
				//TThostFtdcVolumeType	CombPosition;
				///组合多头冻结
				//TThostFtdcVolumeType	CombLongFrozen;
				///组合空头冻结
				//TThostFtdcVolumeType	CombShortFrozen;
				///逐日盯市平仓盈亏
				//TThostFtdcMoneyType	CloseProfitByDate;
				///逐笔对冲平仓盈亏
				//TThostFtdcMoneyType	CloseProfitByTrade;
				///今日持仓
				//pos.TodayPosition;
				///保证金率
				//pos.MarginRateByMoney = code->LongMarginRatio;
				///保证金率(按手数)
				//TThostFtdcRatioType	MarginRateByVolume;
				///执行冻结
				//TThostFtdcVolumeType	StrikeFrozen;
				///执行冻结金额
				//TThostFtdcMoneyType	StrikeFrozenAmount;
				///放弃执行冻结
				//TThostFtdcVolumeType	AbandonFrozen;
				///交易所代码
				strcpy(pos.ExchangeID, order->ExchangeID);
				///执行冻结的昨仓
				//TThostFtdcVolumeType	YdStrikeFrozen;
				///投资单元代码
				//TThostFtdcInvestUnitIDType	InvestUnitID;
				///大商所持仓成本差值，只有大商所使用
				//TThostFtdcMoneyType	PositionCostOffset;
				///tas持仓手数
				//TThostFtdcVolumeType	TasPosition;
				///tas持仓成本
				//TThostFtdcMoneyType	TasPositionCost;
				position = std::make_shared<CTPPositionInfo>(pos);
				short_positions_[position->id] = position;
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				//pos.LongFrozenAmount += ;
				///开仓冻结金额
				pos.ShortFrozenAmount += margin;
				//}
			}
			user_->update_position(position);
			//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
			//空开，冻结资金
			account_->FrozenMargin += margin;
			account_->Available -= margin;
			user_->update_account(account_);
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_NoTradeQueueing);
		}
	}
	else {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			//
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				if (test_date_) {
					price = order->LimitPrice;
				}
				else {
					price = code->Close;
				}
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->ShortMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : short_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//{
				///多头冻结
				//pos.LongFrozen += volume;
				///空头冻结
				pos.ShortFrozen += volume;
				///开仓冻结金额
				//pos.LongFrozenAmount = ;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//{
			//买平，冻结空头持仓
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_NoTradeQueueing);
		}
		else {
			double price = 0;
			int volume = 0;
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				if (test_date_) {
					price = order->LimitPrice;
				}
				else {
					price = code->Close;
				}
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->LongMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : long_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//{
				///多头冻结
				pos.LongFrozen += volume;
				///空头冻结
				//pos.ShortFrozen += volume;
				///开仓冻结金额
				//pos.LongFrozenAmount = ;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//{
			//卖平，冻结多头持仓
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_NoTradeQueueing);
		}
	}
}

void CTPTrader::mock_cancel(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order)
{
	if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			//
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = code->Close;
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->LongMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : long_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				pos.LongFrozenAmount -= margin;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
			//开多，冻结资金
			account_->FrozenMargin -= margin;
			account_->Available += margin;
			user_->update_account(account_);
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_Canceled);
		}
		else {
			double price = 0;
			int volume = 0;
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = code->Close;
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->ShortMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : short_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				///多头冻结
				//pos.LongFrozen;
				///空头冻结
				//TThostFtdcVolumeType	ShortFrozen;
				///开仓冻结金额
				//pos.LongFrozenAmount += ;
				///开仓冻结金额
				pos.ShortFrozenAmount -= margin;
				//}
			}
			user_->update_position(position);
			//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
			//空开，冻结资金
			account_->FrozenMargin -= margin;
			account_->Available += margin;
			user_->update_account(account_);
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_Canceled);
		}
	}
	else {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			//
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = code->Close;
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->ShortMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : short_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//{
				///多头冻结
				//pos.LongFrozen += volume;
				///空头冻结
				pos.ShortFrozen -= volume;
				///开仓冻结金额
				//pos.LongFrozenAmount = ;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//{
			//买平，冻结空头持仓
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_Canceled);
		}
		else {
			double price = 0;
			int volume = 0;
			volume = order->VolumeTotal;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = code->Close;
			} break;
			case ORDER_LIMIT:
			default: {
				price = order->LimitPrice;
			} break;
			}
			double amount = price * volume * code->VolumeMultiple;
			double margin = amount * code->LongMarginRatio;
			//更新持仓和资金
			std::shared_ptr<CTPPositionInfo> position;
			for (auto& pr : long_positions_)
			{
				if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
					position = pr.second;
					break;
				}
			}
			if (!position) {
				ASSERT(0);
			}
			else {
				CThostFtdcInvestorPositionField& pos = *position;
				//{
				///多头冻结
				pos.LongFrozen -= volume;
				///空头冻结
				//pos.ShortFrozen += volume;
				///开仓冻结金额
				//pos.LongFrozenAmount = ;
				///开仓冻结金额
				//TThostFtdcMoneyType	ShortFrozenAmount;
				//}
			}
			user_->update_position(position);
			//{
			//卖平，冻结多头持仓
			//}
			//更新订单
			mock_update_order(code, order, THOST_FTDC_OST_Canceled);
		}
	}
}

void CTPTrader::mock_match(zqdb::CodeT<CTPCODEINFO> &code, std::shared_ptr<CTPOrderInfo> &order)
{
	//委托和行情变动时模拟撮合
	uint32_t date = 0, tradeday = 0;
	uint32_t time = code.GetNowTime(&date, &tradeday);
	double close = code->Close; //最新价
	if (test_date_) {
		date = test_date_;
		time = test_time_;
		close = order->LimitPrice;
	}
	if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = close;
				volume = order->VolumeTotal;
			} break;
			case ORDER_LIMIT: 
			default: {
				if (order->LimitPrice >= close) {
					price = close;
					volume = order->VolumeTotal;
				}
			} break;
			}
			if (volume) {
				double amount = price * volume * code->VolumeMultiple;
				double margin = amount * code->LongMarginRatio;
				//更新持仓和资金
				std::shared_ptr<CTPPositionInfo> position;
				for (auto& pr : long_positions_)
				{
					if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
						position = pr.second;
						break;
					}
				}
				if (!position) {
					ASSERT(0);
				}
				else {
					CThostFtdcInvestorPositionField& pos = *position;
					//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
					///今日持仓
					pos.Position += volume;
					///多头冻结
					//pos.LongFrozen;
					///空头冻结
					//TThostFtdcVolumeType	ShortFrozen;
					///开仓冻结金额
					pos.LongFrozenAmount -= amount;
					///开仓冻结金额
					//TThostFtdcMoneyType	ShortFrozenAmount;
					///开仓量
					pos.OpenVolume += volume;
					///开仓金额
					pos.OpenAmount += amount;
					///开仓成本
					pos.OpenCost += amount;
					///今日持仓
					pos.TodayPosition += volume;
					///占用的保证金
					pos.UseMargin += margin;
					///持仓成本
					pos.PositionCost += amount;
					//}
				}
				user_->update_position(position);
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				//开多成交，释放冻结
				account_->FrozenMargin -= margin;
				account_->CurrMargin += margin;
				//account_->Available -= margin; //match_queue已经减过了
				user_->update_account(account_);
				//}
				//更新订单
				mock_update_order(code, order, THOST_FTDC_OST_AllTraded, volume);
				//推送成交
				mock_new_trade(code, order, price, volume);
			}
		}
		else {
			double price = 0;
			int volume = 0;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = close;
				volume = order->VolumeTotal;
			} break;
			case ORDER_LIMIT:
			default: {
				if (order->LimitPrice <= close) {
					price = close;
					volume = order->VolumeTotal;
				}
			} break;
			}
			if (volume) {
				double amount = price * volume * code->VolumeMultiple;
				double margin = amount * code->ShortMarginRatio;
				//更新持仓和资金
				std::shared_ptr<CTPPositionInfo> position;
				for (auto& pr : short_positions_)
				{
					if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
						position = pr.second;
						break;
					}
				}
				if (!position) {
					ASSERT(0);
				}
				else {
					CThostFtdcInvestorPositionField& pos = *position;
					//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
					///今日持仓
					pos.Position += volume;
					///多头冻结
					//pos.LongFrozen;
					///空头冻结
					//TThostFtdcVolumeType	ShortFrozen;
					///开仓冻结金额
					//pos.LongFrozenAmount -= ;
					///开仓冻结金额
					pos.ShortFrozenAmount -= margin;
					///开仓量
					pos.OpenVolume += volume;
					///开仓金额
					pos.OpenAmount += amount;
					///开仓成本
					pos.OpenCost += amount;
					///今日持仓
					pos.TodayPosition += volume;
					///占用的保证金
					pos.UseMargin += margin;
					///持仓成本
					pos.PositionCost += amount;
					//}
				}
				user_->update_position(position);
				//if (order->CombOffsetFlag[0] == THOST_FTDC_OF_Open) {
				//开空成交，释放冻结
				account_->FrozenMargin -= margin;
				account_->CurrMargin += margin;
				//account_->Available -= margin; //match_queue已经减过了
				user_->update_account(account_);
				//}
				//更新订单
				mock_update_order(code, order, THOST_FTDC_OST_AllTraded, volume);
				//推送成交
				mock_new_trade(code, order, price, volume);
			}
		}
	}
	else {
		if (order->Direction == THOST_FTDC_D_Buy) {
			double price = 0;
			int volume = 0;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = close;
				volume = order->VolumeTotal;
			} break;
			case ORDER_LIMIT:
			default: {
				if (order->LimitPrice >= close) {
					price = close;
					volume = order->VolumeTotal;
				}
			} break;
			}
			if (volume) {
				double amount = price * volume * code->VolumeMultiple;
				double margin = amount * code->ShortMarginRatio;
				//更新持仓和资金
				std::shared_ptr<CTPPositionInfo> position;
				for (auto& pr : short_positions_)
				{
					if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
						position = pr.second;
						break;
					}
				}
				double UseMargin = 0;
				double CloseProfit = 0;
				if (!position) {
					ASSERT(0);
				}
				else {
					CThostFtdcInvestorPositionField& pos = *position;
					//{
					UseMargin = pos.UseMargin / pos.Position * volume;
					double OpenCostPrice = pos.OpenCost / pos.OpenVolume / code->VolumeMultiple;
					CloseProfit = (OpenCostPrice - price) * volume * code->VolumeMultiple;
					///今日持仓
					pos.Position -= volume;
					///多头冻结
					//pos.LongFrozen -= volume;
					///空头冻结
					pos.ShortFrozen -= volume;
					///开仓冻结金额
					//pos.LongFrozenAmount;
					///开仓冻结金额
					//TThostFtdcMoneyType	ShortFrozenAmount;
					///平仓量
					pos.CloseVolume += volume;
					///平仓金额
					pos.CloseAmount += amount;
					///开仓成本
					//pos.OpenCost -= amount;
					///今日持仓
					pos.TodayPosition -= volume;
					///占用的保证金
					pos.UseMargin = std::max<double>(pos.UseMargin - UseMargin, 0);
					///持仓成本
					pos.PositionCost -= amount;
					///平仓盈亏
					pos.CloseProfit += CloseProfit;
					//}
				}
				user_->update_position(position);
				//{
				//买平成交,空头持仓减少,释放资金
				account_->CloseProfit += CloseProfit;
				account_->CurrMargin = std::max<double>(account_->CurrMargin - UseMargin, 0);
				account_->Available += margin;
				user_->update_account(account_);
				//}
				//更新订单
				mock_update_order(code, order, THOST_FTDC_OST_AllTraded, volume);
				//推送成交
				mock_new_trade(code, order, price, volume);
			}
		}
		else {
			double price = 0;
			int volume = 0;
			auto order_type = ORDERTYPE_CTP2VT(order->OrderPriceType, order->TimeCondition, order->VolumeCondition);
			switch (order_type)
			{
			case ORDER_FAK:
			case ORDER_FOK:
			case ORDER_MARKET: {
				price = close;
				volume = order->VolumeTotal;
			} break;
			case ORDER_LIMIT:
			default: {
				if (order->LimitPrice <= close) {
					price = close;
					volume = order->VolumeTotal;
				}
			} break;
			}
			if (volume) {
				double amount = price * volume * code->VolumeMultiple;
				double margin = amount * code->LongMarginRatio;
				//更新持仓和资金
				std::shared_ptr<CTPPositionInfo> position;
				for (auto& pr : long_positions_)
				{
					if (stricmp(code->TradeCode, pr.second->InstrumentID) == 0) {
						position = pr.second;
						break;
					}
				}
				double UseMargin = 0;
				double CloseProfit = 0;
				if (!position) {
					ASSERT(0);
				}
				else {
					CThostFtdcInvestorPositionField& pos = *position;
					//{
					UseMargin = pos.UseMargin / pos.Position * volume;
					double OpenCostPrice = pos.OpenCost / pos.OpenVolume / code->VolumeMultiple;
					CloseProfit = (price - OpenCostPrice) * volume * code->VolumeMultiple;
					///今日持仓
					pos.Position -= volume;
					///多头冻结
					pos.LongFrozen -= volume;
					///空头冻结
					//pos.ShortFrozen -= volume;
					///开仓冻结金额
					//pos.LongFrozenAmount;
					///开仓冻结金额
					//TThostFtdcMoneyType	ShortFrozenAmount;
					///平仓量
					pos.CloseVolume += volume;
					///平仓金额
					pos.CloseAmount += amount;
					///开仓成本
					//pos.OpenCost -= amount;
					///今日持仓
					pos.TodayPosition -= volume;
					///占用的保证金
					pos.UseMargin = std::max<double>(pos.UseMargin - UseMargin, 0);
					///持仓成本
					pos.PositionCost -= amount;
					///平仓盈亏
					pos.CloseProfit += CloseProfit;
					//}
				}
				user_->update_position(position);
				//{
				//买平成交，多头持仓减少,释放资金
				account_->CloseProfit += CloseProfit;
				account_->CurrMargin = std::max<double>(account_->CurrMargin - UseMargin, 0);
				account_->Available += margin;
				user_->update_account(account_);
				//}
				//更新订单
				mock_update_order(code, order, THOST_FTDC_OST_AllTraded, volume);
				//推送成交
				mock_new_trade(code, order, price, volume);
			}
		}
	}
}

void CTPTrader::on_timer_for_reconnect(const boost::system::error_code& ec)
{
	if (ec) {
		return;
	}

	if (!api_) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		LOG4W(STR_MODULE_NAME " %s timeout", userid_.c_str());
		if (first_login_flag_ == FIRST_LOGIN_FAILED) {
			//
		}
		else {
			on_disconnect();
			set_offline();
			set_online();
		}
	}
}

void CTPTrader::on_timer_for_requery(const boost::system::error_code& ec)
{
	if (ec) {
		return;
	}

	register_timer_for_reconnect();

	if (IsStateful(CTP_STAT_MAX)) {
		//ASSERT(0);
	}
	else {
		ResetInState();
		on_init_next();
	}
}

void CTPTrader::on_timer_for_refresh(const boost::system::error_code& ec)
{
	if (ec) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		//ASSERT(0);
	}
	else {
		if (!IsAnyInStateful()) {
			//继续刷新资金和持仓
			SetState({ CTP_STAT_TRADINGACCOUNT, CTP_STAT_POSITION }, false);
			on_init_next();
		}
		register_timer_for_refresh();
	}
}

void CTPTrader::clear()
{
	init_flag_ = false;
	//
	unreg_notify();
	//
	memset(&m_AuthInfo, 0, sizeof(m_AuthInfo)); //身份认证信息
	memset(&m_UserInfo, 0, sizeof(m_UserInfo)); //登录信息
	m_OrderRef = 0;

	memset(&m_InvestorInfo, 0, sizeof(m_InvestorInfo)); //投资者信息
														//memset(&m_TradingAccount, 0, sizeof(m_TradingAccount)); //交易账户
	memset(&m_TradingCode, 0, sizeof(m_TradingCode)); //交易编码

													  //m_SettlementInfo
													  //m_SettlementConfirm; //结算单确认

													  //m_NoticeInfo;	//通知

													  //memset(&m_CFMMCKeyInfo,0,sizeof(m_CFMMCKeyInfo)); //保证金监管系统经纪公司资金账户密钥

	ctp_commoditys_.clear();
	ctp_products_.clear();
	ctp_exchanges_.clear();
	account_.reset();
	orders_.clear();
	trades_.clear();
	long_positions_.clear();
	short_positions_.clear();
	init_status_.clear();
	if (user_) {
		user_->clear();
	}
	ResetAllState();
}

void CTPTrader::on_connect()
{
	if (is_stop()) {
		return;
	}
	if (IsStateful(CTP_STAT_CONNECT)) {
		//LOG4I(STR_MODULE_NAME " %s CTPTrader Already OnFrontConnected", userid_.c_str());
		return;
	}
	LOG4I(STR_MODULE_NAME " %s trade connect", userid_.c_str());
	if (req_login_) {
		do_login_response(u8"连接成功，登录中...");
	}
	if (MDMgr::Inst().is_initing()) {
		SetState(CTP_STAT_CONNECT);
		//等待行情初始化完成，初始化完成后会调用clear/init_new_tradingday,这时会重新offline/online
		LOG4I(STR_MODULE_NAME " %s market is initing", userid_.c_str());
		return;
	}
	else {
		if (user_) {
			user_->Status = USER_STATUS_CONNECTED;
			if (user_->h) {
				user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
			}
		}
		clear();
		SetState(CTP_STAT_CONNECT);
		on_init_next();
		register_timer_for_reconnect();
	}
}

void CTPTrader::on_disconnect()
{
	if (is_stop()) {
		return;
	}
	if (IsInStateful(CTP_STAT_CONNECT)) {
		//LOG4I(STR_MODULE_NAME " %s CTPTrader Already OnFrontDisconnected", userid_.c_str());
		return;
	}
	LOG4I(STR_MODULE_NAME " %s trade disconnect", userid_.c_str());
	//CTP会自动重连
	unregister_timer();
	if (user_) {
		user_->Status = USER_STATUS_CONNECT;
		if (user_->h) {
			user_->h = TDMgr::Inst().update_user(user_->h, user_.get());
		}
	}
	clear();
	if (req_login_) {
		do_login_err_response(ZQDB_STATUS_ERROR, u8"连接失败，请稍后重试");
		TDMgr::Inst().remove_trader(userinfo_.UserID);
	}
	SetInState(CTP_STAT_CONNECT);
}

int CTPTrader::NextRequestID()
{
	static int _nRequestID = 0;
	return ++_nRequestID;
}

bool CTPTrader::IsNeedRequestAndSet(int nStatus)
{
	//std::unique_lock<std::recursive_mutex> lock(mutex_);
	if (IsStateful(nStatus) || IsInStateful(nStatus))
	{
		return false;
	}
	else
	{
		SetInState(nStatus);
		return true;
	}
}

void CTPTrader::on_init_done(int status)
{
	if (is_stop()) {
		return;
	}
	SetState(status);
	on_init_next();
}

void CTPTrader::on_init_next()
{
	if (is_stop()) {
		return;
	}

	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	const int nStatus[] =
	{
		CTP_STAT_AUTHENTICATE,	//认证
		CTP_STAT_LOGIN,	//登录
		CTP_STAT_INVESTORINFO,	//投资者信息
								//CTP_STAT_TRADINGACCOUNT,	//交易账户
								CTP_STAT_TRADINGCODE,	//交易编码
														//CTP_STAT_NOTICE,	//公告通知
														//CTP_STAT_CFMMC,	//保证金监管系统经纪公司资金账户密钥
														CTP_STAT_QRYSETTLEMENTINFOCONFIRM,	//查询结算单确认
														CTP_STAT_QRYSETTLEMENTINFO,	//查询结算单
														CTP_STAT_SETTLEMENTINFOCONFIRM,	//结算单确认
														CTP_STAT_EXCHANGE,				   //市场列表
														CTP_STAT_PRODUCT,				   //产品列表
														CTP_STAT_INSTRUMENT,			   //合约列表
														CTP_STAT_DEPTHMARKETDATA,		   //
														CTP_STAT_COMMISSIONRATE,
														CTP_STAT_ORDER,
														CTP_STAT_TRADE,
														CTP_STAT_POSITION,
														CTP_STAT_TRADINGACCOUNT,
	};
	for (int i = base_flag_ ? 0 : 4, j = sizeof(nStatus) / sizeof(long); i < j; i++)
	{
		if (IsNeedRequestAndSet(nStatus[i]))
		{
			int rlt = -1;
			int nRequestID = NextRequestID();
			switch (nStatus[i])
			{
			case CTP_STAT_AUTHENTICATE:
			{
				if (userinfo_.ProductInfo[0] || userinfo_.AuthCode[0])
				{
					CThostFtdcReqAuthenticateField req = { 0 };
					memcpy(req.BrokerID, userinfo_.BrokerID, sizeof(userinfo_.BrokerID));
					memcpy(req.UserID, userinfo_.UserID, sizeof(userinfo_.UserID));
					memcpy(req.UserProductInfo, userinfo_.ProductInfo, sizeof(userinfo_.ProductInfo));
					memcpy(req.AuthCode, userinfo_.AuthCode, sizeof(userinfo_.AuthCode));
					memcpy(req.AppID, userinfo_.AppID, sizeof(userinfo_.AppID));
					DoRequest(api_->ReqAuthenticate, req, nRequestID);
				}
				else
				{
					rlt = 0;
					CThostFtdcRspAuthenticateField rsp = { 0 };
					CThostFtdcRspInfoField rspInfo = { 0 };
					on_authenticate(rsp, rspInfo, true);
				}
			}
			break;
			case CTP_STAT_LOGIN:
			{
				LOG4I(STR_MODULE_NAME " %s ReqUserLogin", userid_.c_str());
				CThostFtdcReqUserLoginField req = { 0 };
				//CThostFtdcReqUserLoginField req = {0};
				//TradingDay;
				memcpy(req.BrokerID, userinfo_.BrokerID, sizeof(userinfo_.BrokerID));
				memcpy(req.UserID, userinfo_.UserID, sizeof(userinfo_.UserID));
				memcpy(req.Password, userinfo_.Password, sizeof(userinfo_.Password));
				memcpy(req.UserProductInfo, m_AuthInfo.UserProductInfo, sizeof(m_AuthInfo.UserProductInfo));
				//InterfaceProductInfo;
				//ProtocolInfo;
				//MacAddress;
				//OneTimePassword;
				//ClientIPAddress;
				DoRequest(api_->ReqUserLogin, req, nRequestID);
			}
			break;
			case CTP_STAT_INVESTORINFO:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryInvestor", userid_.c_str());
				CThostFtdcQryInvestorField req = { 0 };
				strcpy(req.BrokerID, userinfo_.BrokerID);
				strcpy(req.InvestorID, userinfo_.UserID);
				DoRequest(api_->ReqQryInvestor, req, nRequestID);
			}
			break;
			case CTP_STAT_TRADINGACCOUNT:
			{
				//LOG4I("ReqQryTradingAccount %s", m_InvestorInfo.InvestorID);
				//RMB(CNY)-人民币 USD-美圆 HKD-港元
				CThostFtdcQryTradingAccountField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				//strcpy(req.CurrencyID, "CNY");
				DoRequest(api_->ReqQryTradingAccount, req, nRequestID);
				if (!IsStateful(CTP_STAT_MAX)) {
					LOG4I(STR_MODULE_NAME " %s ReqQryTradingAccount[%d]", userid_.c_str(), rlt);
				};
			}
			break;
			case CTP_STAT_TRADINGCODE:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryTradingCode %s", userid_.c_str(), m_InvestorInfo.InvestorID);
				CThostFtdcQryTradingCodeField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				/*if(CLIENT_ID != NULL)
				strcpy_s(req.ClientID,CLIENT_ID);
				if(EXCHANGE_ID != NULL)
				strcpy_s(req.ExchangeID,EXCHANGE_ID);*/
				DoRequest(api_->ReqQryTradingCode, req, nRequestID);
			}
			break;
			case CTP_STAT_NOTICE:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryNotice", userid_.c_str());
				CThostFtdcQryNoticeField  req = { 0 };
				strcpy(req.BrokerID, userinfo_.BrokerID);
				DoRequest(api_->ReqQryNotice, req, nRequestID);
			}
			break;
			case CTP_STAT_CFMMC:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryCFMMCTradingAccountKey %s", userid_.c_str(), m_InvestorInfo.InvestorID);
				CThostFtdcQryCFMMCTradingAccountKeyField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				DoRequest(api_->ReqQryCFMMCTradingAccountKey, req, nRequestID);
			}
			break;
			case CTP_STAT_QRYSETTLEMENTINFOCONFIRM:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQrySettlementInfoConfirm %s", userid_.c_str(), m_InvestorInfo.InvestorID);
				CThostFtdcQrySettlementInfoConfirmField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				DoRequest(api_->ReqQrySettlementInfoConfirm, req, nRequestID);
			}
			break;
			case CTP_STAT_QRYSETTLEMENTINFO:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQrySettlementInfo %s", userid_.c_str(), m_InvestorInfo.InvestorID);
				CThostFtdcQrySettlementInfoField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				//req.TradingDay;
				DoRequest(api_->ReqQrySettlementInfo, req, nRequestID);
			}
			break;
			case CTP_STAT_SETTLEMENTINFOCONFIRM:
			{
				LOG4I(STR_MODULE_NAME " %s ReqSettlementInfoConfirm %s", userid_.c_str(), m_InvestorInfo.InvestorID);
				CThostFtdcSettlementInfoConfirmField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				//ConfirmDate	//rsp
				//ConfirmTime	//rsp
				DoRequest(api_->ReqSettlementInfoConfirm, req, nRequestID);
			}
			break;
			case CTP_STAT_EXCHANGE:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryExchange", userid_.c_str());
				CThostFtdcQryExchangeField req = { 0 };
				DoRequest(api_->ReqQryExchange, req, nRequestID);
			}
			break;
			case CTP_STAT_PRODUCT:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryProduct", userid_.c_str());
				CThostFtdcQryProductField req = { 0 };
				//req.ProductID
				//req.ProductClass;
				DoRequest(api_->ReqQryProduct, req, nRequestID);
			}
			break;
			case CTP_STAT_INSTRUMENT:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryInstrument", userid_.c_str());
				CThostFtdcQryInstrumentField req = { 0 };
				//req.InstrumentID;
#if 0
				strcpy(req.ExchangeID, "DCE");
#endif//
				//req.ExchangeInstID;
				//req.ProductID;
				DoRequest(api_->ReqQryInstrument, req, nRequestID);
			}
			break;
			case CTP_STAT_DEPTHMARKETDATA:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryDepthMarketData", userid_.c_str());
				CThostFtdcQryDepthMarketDataField req = { 0 };
				DoRequest(api_->ReqQryDepthMarketData, req, nRequestID);
			}
			break;
			case CTP_STAT_COMMISSIONRATE:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryInstrumentCommissionRate", userid_.c_str());
				CThostFtdcQryInstrumentCommissionRateField req = { 0 };
				//strcpy(req.ExchangeID, EXCHANGE_SHFE);
				DoRequest(api_->ReqQryInstrumentCommissionRate, req, nRequestID);
			}
			break;
			case CTP_STAT_ORDER:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryOrder", userid_.c_str());
				CThostFtdcQryOrderField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				DoRequest(api_->ReqQryOrder, req, nRequestID);
			}
			break;
			case CTP_STAT_TRADE:
			{
				LOG4I(STR_MODULE_NAME " %s ReqQryTrade", userid_.c_str());
				CThostFtdcQryTradeField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				DoRequest(api_->ReqQryTrade, req, nRequestID);
			}
			break;
			case CTP_STAT_POSITION:
			{
				//LOG4I("ReqQryInvestorPosition");
				CThostFtdcQryInvestorPositionField req = { 0 };
				strcpy(req.BrokerID, m_InvestorInfo.BrokerID);
				strcpy(req.InvestorID, m_InvestorInfo.InvestorID);
				DoRequest(api_->ReqQryInvestorPosition, req, nRequestID);
				if (!IsStateful(CTP_STAT_MAX)) {
					LOG4I(STR_MODULE_NAME " %s ReqQryInvestorPosition[%d]", userid_.c_str(), rlt);
				};
			}
			break;
			default:
				break;
			}
			//这里如果出错，定时器会重新set_online的
			return;
		}
	}

	//只有没有任何在途状态且状态还没有CTP_STAT_MAX，则进入normal
	if (!IsAnyInStateful() && !IsStateful(CTP_STAT_MAX)) {

		unregister_timer();

		auto old_trading_day = g_module_info->tradingday;
		auto trading_day = CTPDate2Date(m_UserInfo.TradingDay);
		LOG4I(STR_MODULE_NAME " %s on_init from %d to %d", userid_.c_str(), old_trading_day, trading_day);
		if (old_trading_day != trading_day) {
			if (!init_flag_) {
				init_flag_ = true;
				if (base_flag_) {

					//主力连续合约: 合约首次上市时, 以当日收盘同品种持仓量最大者作为从第二个交易日开始的主力合约.
					//当同品种其他合约持仓量在收盘后超过当前主力合约 1.1 倍时, 从第二个交易日开始进行主力合约的切换.
					//日内不会进行主力合约的切换.主力连续合约是由该品种期货不同时期主力合约接续而成.
					//前者为合约量价数据的简单拼接, 未做平滑处理; 后者对价格进行了”平滑”处理, 处理规则如下:
					//以主力合约切换前一天(T - 1日)新、旧两个主力合约收盘价做差, 
					//之后将 T - 1 日及以前的主力连续合约的所有价格水平整体加上或减去该价差, 
					//以”整体抬升”或”整体下降”主力合约的价格水平, 成交量、持仓量均不作调整, 成交额统一设置为 0.
					//指数连续合约 : 由当前品种全部可交易合约以累计持仓量为权重加权平均得到

					//初始化主力、次主力
					for (auto it : ctp_commoditys_)
					{
						auto& commodity = it.second;
						auto& main_commodity = ctp_products_[commodity->Product]->main_commodity_;
						auto& second_commodity = ctp_products_[commodity->Product]->second_commodity_;
						if (main_commodity) {
							if (main_commodity->PreOpenInterest < commodity->PreOpenInterest) {
								second_commodity = main_commodity;
								main_commodity = commodity;
							}
							else if (second_commodity) {
								if (second_commodity->PreOpenInterest < commodity->PreOpenInterest) {
									second_commodity = commodity;
								}
							}
							else {
								second_commodity = commodity;
							}
						}
						else {
							second_commodity = main_commodity;
							main_commodity = commodity;
						}
					}
					//校正主力、次主力
					std::set<std::string> main;
					boost::split(main, Manager::Inst().info().get<std::string>("main", ""), boost::is_any_of(","));
					for (auto code : main) {
						auto it = ctp_commoditys_.find(code.c_str());
						if (it != ctp_commoditys_.end()) {
							if (it->second->product_->main_commodity_ != it->second) {
								if (it->second->product_->second_commodity_ == it->second) {
									it->second->product_->main_commodity_.swap(it->second->product_->second_commodity_);
								}
								else {
									it->second->product_->main_commodity_ = it->second;
								}
							}
						}
					}
					//切换主力、次主力
					std::ostringstream oss;
					for (auto& pr : ctp_products_)
					{
						if (pr.second->main_commodity_) {
							if (pr.second->second_commodity_) {
								if (pr.second->second_commodity_->PreOpenInterest > (1.1 * pr.second->main_commodity_->PreOpenInterest)) {
									pr.second->main_commodity_.swap(pr.second->second_commodity_);
								}
							}
							oss << pr.second->main_commodity_->Code << ",";
						}
					}
					auto str = oss.str();
					Manager::Inst().info().put("main", str);
					str = Manager::Inst().info().get<std::string>("main", "");
					boost::split(main, str, boost::is_any_of(","));

					auto& inst = MDMgr::Inst();
					inst.service().post(std::bind(&MDMgr::on_new_tradingday, &inst
						, trading_day, ctp_exchanges_, ctp_products_, ctp_commoditys_));
				}
				else {
					//这里等待init_new_tradingday
				}
			}
			else {
				//ASSERT(0);
				//这里等待init_new_tradingday
			}
		}
		else {
			if (base_flag_) {
				//行情
				auto& inst = MDMgr::Inst();
				inst.service().post(std::bind(&MDMgr::on_normal, &inst, false));
				//交易
				auto& td_inst = TDMgr::Inst();
				td_inst.service().post(boost::bind(&TDMgr::on_normal, &td_inst, false));
				//管理
				auto& mgr = Manager::Inst();
				inst.service().post(std::bind(&Manager::on_normal, &mgr, false));
			}
			on_normal();
		}
	}
}

void CTPTrader::on_authenticate(const CThostFtdcRspAuthenticateField& rspAuthenticateField, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
{
	if (is_stop()) {
		return;
	}
	if (bIsLast)
		LOG4I(STR_MODULE_NAME " %s on_authenticate %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
	if (rspAuthenticateField.UserID[0]) {
		m_AuthInfo = rspAuthenticateField;
	}
	on_init_done(CTP_STAT_AUTHENTICATE);
}

void CTPTrader::on_login(const CThostFtdcRspUserLoginField& rspUserLogin, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
{
	if (is_stop()) {
		return;
	}
	login_time_ = std::chrono::system_clock::now();
	if (!IsErrorRspInfo(&rspInfo)) {
		m_UserInfo = rspUserLogin;
		m_OrderRef = atoi(m_UserInfo.MaxOrderRef);
		if (first_login_flag_ == FIRST_LOGIN_LOGING) {
			first_login_flag_ = FIRST_LOGIN_SUCESS;
		}
		else {
		}
		/*auto old_trading_day = MDMgr::Inst().tradingday();
		auto trading_day = CTPDate2Date(m_UserInfo.TradingDay);
		LOG4I("ctp on_login from %d to %d", old_trading_day, trading_day);
		if (trading_day != old_trading_day) {
			//
		}*/
		on_init_done(CTP_STAT_LOGIN);
	}
	else {
		auto errmsg = gbk_to_utf8(rspInfo.ErrorMsg);
		LOG4I(STR_MODULE_NAME  "%s login failed[%d:%s]", userid_.c_str(), rspInfo.ErrorID, errmsg.c_str());
		if (base_flag_) {
			//
		}
		else {
			if (first_login_flag_ == FIRST_LOGIN_LOGING) {
				first_login_flag_ = FIRST_LOGIN_FAILED;
			}
			else {
				//不再重登陆，等下次断开重连会再尝试登陆
			}
			if (req_login_) {
				//第一次登陆用户失败，直接通知登陆失败，删除用户
				do_login_err_response(ZQDB_STATUS_ERROR, errmsg.c_str());
				TDMgr::Inst().remove_trader(userinfo_.UserID);
			}
		}
	}
}

	void CTPTrader::on_add_settlement(const CThostFtdcSettlementInfoField& settlementInfo, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
	{
		if (is_stop()) {
			return;
		}
		if (settlementInfo.InvestorID[0]) {
			m_SettlementInfo = settlementInfo;
		}
		if (bIsLast) {
			LOG4I(STR_MODULE_NAME " %s on_add_settlement %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
			on_init_done(CTP_STAT_QRYSETTLEMENTINFO);
		}
	}

	void CTPTrader::on_settlement_confirm(const CThostFtdcSettlementInfoConfirmField& settlementInfoConfirm, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
	{
		if (is_stop()) {
			return;
		}
		if (bIsLast)
			LOG4I(STR_MODULE_NAME " %s on_settlement_confirm %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
		if (settlementInfoConfirm.InvestorID[0]) {
			m_SettlementConfirm = settlementInfoConfirm;
		}
		on_init_done(CTP_STAT_SETTLEMENTINFOCONFIRM);
	}

	void CTPTrader::on_add_settlement_confirm(const CThostFtdcSettlementInfoConfirmField& settlementInfoConfirm, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
	{
		if (is_stop()) {
			return;
		}
		if (settlementInfoConfirm.InvestorID[0]) {
			m_SettlementConfirm = settlementInfoConfirm;
			if (stricmp(m_UserInfo.TradingDay, m_SettlementConfirm.ConfirmDate) == 0) {
				//说明已经查询结算过了
				SetState(CTP_STAT_QRYSETTLEMENTINFO);
				SetState(CTP_STAT_SETTLEMENTINFOCONFIRM);
			}
			else {
				//后面会先查询结算单，再通知上层确认结算单
			}
		}
		if (bIsLast) {
			LOG4I(STR_MODULE_NAME " %s on_add_settlement_confirm %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
			on_init_done(CTP_STAT_QRYSETTLEMENTINFOCONFIRM);
		}
	}

	void CTPTrader::on_add_investor(const CThostFtdcInvestorField& investor, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
	{
		if (is_stop()) {
			return;
		}
		if (investor.InvestorID[0]) {
			m_InvestorInfo = investor;
		}
		if (bIsLast) {
			LOG4I(STR_MODULE_NAME " %s on_add_investor %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
			on_init_done(CTP_STAT_INVESTORINFO);
		}
	}

	void CTPTrader::on_add_trading_code(const CThostFtdcTradingCodeField& tradingCode, const CThostFtdcRspInfoField& rspInfo, bool bIsLast)
	{
		if (is_stop()) {
			return;
		}
		if (tradingCode.InvestorID[0]) {
			m_TradingCode = tradingCode;
		}
		if (bIsLast) {
			LOG4I(STR_MODULE_NAME " %s on_add_trading_code %d %s", userid_.c_str(), rspInfo.ErrorID, gbk_to_utf8(rspInfo.ErrorMsg).c_str());
			on_init_done(CTP_STAT_TRADINGCODE);
		}
	}

void CTPTrader::on_add_exchange(const std::shared_ptr<CTPExchangeInfoEx>& exchange)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_EXCHANGE) && !IsStateful(CTP_STAT_EXCHANGE));
	for (auto& str : all_exchange)
	{
		if (stricmp(str, exchange->Exchange) == 0) {
			ctp_exchanges_[exchange->Exchange] = exchange;
			break;
		}
	}
}

void CTPTrader::on_add_product(const std::shared_ptr<CTPProductInfoEx>& product)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_PRODUCT) && !IsStateful(CTP_STAT_PRODUCT));
	auto it = ctp_exchanges_.find(product->Exchange);
	if (it != ctp_exchanges_.end()) {
		product->exchange_ = it->second;
		ctp_products_[product->Product] = product;
	}
	else {
		//ASSERT(0);
	}
}

void CTPTrader::on_add_commodity(const std::shared_ptr<CTPCommodityInfoEx>& commodity)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_INSTRUMENT) && !IsStateful(CTP_STAT_INSTRUMENT));
	auto it = ctp_products_.find(commodity->Product);
	if (it != ctp_products_.end()) {
		commodity->product_ = it->second;
		ctp_commoditys_[commodity->Code] = commodity;
	}
	else {
		//ASSERT(0);
	}
}

void CTPTrader::on_market_data_init(const CThostFtdcDepthMarketDataField& data)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_DEPTHMARKETDATA) && !IsStateful(CTP_STAT_DEPTHMARKETDATA));
	auto it = ctp_commoditys_.find(data.InstrumentID);
	if (it == ctp_commoditys_.end()) {
		return;
	}
	CThostFtdcDepthMarketDataField& src_data = *it->second;
	src_data = data;
}

void CTPTrader::on_add_commission_rate(const CThostFtdcInstrumentCommissionRateField& commission)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_COMMISSIONRATE) && !IsStateful(CTP_STAT_COMMISSIONRATE));
	//LOG4D("%s %.6lf %.6lf", commission.InstrumentID, commission.OpenRatioByMoney, commission.OpenRatioByVolume);
	auto it = ctp_products_.find(commission.InstrumentID);
	if (it == ctp_products_.end()) {
		return;
	}
	CThostFtdcInstrumentCommissionRateField& src_data = *it->second;
	src_data = commission;
}

void CTPTrader::on_init_account(const std::shared_ptr<CTPAccountInfo>& account)
{
	if (is_stop()) {
		return;
	}
	account_ = account;
}

void CTPTrader::on_add_order(const std::shared_ptr<CTPOrderInfo>& order)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_ORDER) && !IsStateful(CTP_STAT_ORDER));
	if (!order)
		return;

	orders_[order->id] = order;
}

void CTPTrader::on_add_trade(const std::shared_ptr<CTPTradeInfo>& trade)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_TRADE) && !IsStateful(CTP_STAT_TRADE));
	if (!trade)
		return;

	trades_[trade->id] = trade;
}

void CTPTrader::on_add_position(const std::shared_ptr<CTPPositionInfo>& position)
{
	if (is_stop()) {
		return;
	}
	ASSERT(IsInStateful(CTP_STAT_POSITION) && !IsStateful(CTP_STAT_POSITION));
	if (!position)
		return;

	if (!position->is_short()) {
		long_positions_[position->id] = position;
	}
	else {
		short_positions_[position->id] = position;
	}
}

void CTPTrader::reg_notify(HZQDB h)
{
	ASSERT(h);
	if (IsRegisterNotify(h)) {
		return;
	}
	RegisterNotify(h, [this](HZQDB h, ZQDB_NOTIFY_TYPE notify) {
		switch (notify)
		{
		case ZQDB_NOTIFY_STATUS: {
		} break;
		case ZQDB_NOTIFY_ADD: {
		} break;
		case ZQDB_NOTIFY_REMOVE: {
		} break;
		case ZQDB_NOTIFY_UPDATE: {
			service().post(boost::bind(&This::on_update, shared_from_this(), h));
		} break;
		}
	});
}

void CTPTrader::unreg_notify()
{
	UnRegisterNotifyAll();
}

void CTPTrader::on_test_login()
{
	if (is_stop()) {
		return;
	}
	//login_result_ = rspUserLoginField;
	if (first_login_flag_ == FIRST_LOGIN_LOGING) {
		first_login_flag_ = FIRST_LOGIN_SUCESS;
	}
	service().post(boost::bind(&This::on_test_init, shared_from_this()));
	service().post(boost::bind(&This::on_test_normal, shared_from_this()));
}

void CTPTrader::on_test_init()
{
	if (is_stop()) {
		return;
	}
}

void CTPTrader::on_test_normal()
{
	if (is_stop()) {
		return;
	}

	double amount = 1000 * 10000;
	if (req_login_) {
		amount = req_login_.GetParamAsDouble("Amount", amount);
	}

	CThostFtdcTradingAccountField account = { 0 };
	strcpy(account.BrokerID, userinfo_.BrokerID);
	strcpy(account.AccountID, userinfo_.UserID);
	account.PreBalance = amount;
	account.PreMargin = 0;
	account.Deposit = 0;
	account.Withdraw = 0;
	account.FrozenMargin = 0;
	account.FrozenCash = 0;
	account.FrozenCommission = 0;
	account.CurrMargin = 0;
	account.Commission = 0;
	account.CloseProfit = 0;
	account.PositionProfit = 0;
	account.Balance = account.PreBalance;
	account.Available = account.PreBalance;
	account.WithdrawQuota = account.PreBalance;
	account.Reserve = account.PreBalance;
	//account.TradingDay
	strcpy(account.CurrencyID, "CNY");
	account_ = std::make_shared<CTPAccountInfo>(account);
	user_->update_account(account_);
	CThostFtdcInvestorField ctp_investor = { 0 };
	strcpy(ctp_investor.BrokerID, userinfo_.BrokerID);
	strcpy(ctp_investor.InvestorID, userinfo_.UserID);
	strcpy(ctp_investor.InvestorName, userinfo_.UserID);
	//strcpy(ctp_investor.InvestorGroupID);
	//ctp_investor.IdentifiedCardType;
	//ctp_investor.IdentifiedCardNo);
	ctp_investor.IsActive = true;
	strcpy(ctp_investor.Telephone, "16888888888");
	strcpy(ctp_investor.Address, "a.b.c");
	strcpy(ctp_investor.OpenDate, "20211203");
	strcpy(ctp_investor.Mobile, "16888888888");
	//strcpy(ctp_investor.CommModelID);
	//strcpy(ctp_investor.MarginModelID);
	user_->update_investor(ctp_investor);
	//strcpy(user_->TradingDay, m_UserInfo.TradingDay);
	//strcpy(user_->LoginTime, m_UserInfo.LoginTime);
	//strcpy(user_->SystemName, m_UserInfo.SystemName);
	user_->FrontID = 10000;
	user_->SessionID = 10001;
	strcpy(user_->MaxOrderRef, "1");
	m_OrderRef = 1;
	user_->Status = USER_STATUS_LOGGED; //用户状态
	user_->h = TDMgr::Inst().update_user(nullptr, user_.get()); //临时处理，一起来就创建用户
																//
	SetState(CTP_STAT_MAX);
	LOG4I(STR_MODULE_NAME " %s normal", userid_.c_str());

	if (req_login_) {
		do_login_err_response(ZQDB_STATUS_OK, u8"登录成功");
	}
}

void CTPTrader::on_normal()
{
	if (is_stop()) {
		return;
	}
	register_timer_for_refresh();

	//更新USER
	if (user_) {
		//
		user_->update_investor(m_InvestorInfo);
		user_->update_account(account_);
		user_->Status = USER_STATUS_LOGGED;
		strcpy(user_->TradingDay, m_UserInfo.TradingDay);
		strcpy(user_->LoginTime, m_UserInfo.LoginTime);
		strcpy(user_->SystemName, m_UserInfo.SystemName);
		user_->FrontID = m_UserInfo.FrontID;
		user_->SessionID = m_UserInfo.SessionID;
		strcpy(user_->MaxOrderRef, m_UserInfo.MaxOrderRef);
		user_->h = TDMgr::Inst().update_user(nullptr, user_.get());
		//
		for (auto& pr : long_positions_)
		{
			auto position = std::make_shared<PositionInfo>();
			position->parent = user_.get();
			position->sp = pr.second;
			position->update();
			user_->long_positions[position->Code] = position;
			reg_notify(position->hcode);
		}
		for (auto& pr : short_positions_)
		{
			auto position = std::make_shared<PositionInfo>();
			position->parent = user_.get();
			position->sp = pr.second;
			position->update();
			user_->short_positions[position->Code] = position;
			reg_notify(position->hcode);
		}
		for (auto& pr : orders_)
		{
			auto order = std::make_shared<OrderInfo>();
			order->parent = user_.get();
			order->sp = pr.second;
			order->update();
			user_->orders[order->Order] = order;
			reg_notify(order->hcode);
		}
		for (auto& pr : trades_)
		{
			auto trade = std::make_shared<TradeInfo>();
			trade->parent = user_.get();
			trade->sp = pr.second;
			trade->update();
			user_->trades[trade->Trade] = trade;
			reg_notify(trade->hcode);
		}
	}

	SetState(CTP_STAT_MAX);
	LOG4I(STR_MODULE_NAME " %s normal", userid_.c_str());

	if (req_login_) {
		do_login_err_response(ZQDB_STATUS_OK, u8"登录成功");
	}

	if (!init_status_.empty()) {
		auto init_status = init_status_;
		init_status_.clear();
		for (auto o : init_status) {
			on_market_status_update(o);
		}
	}
}

void CTPTrader::on_market_data_udpate(const CThostFtdcDepthMarketDataField& data)
{
	if (is_stop()) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		return;
	}

	MDMgr::Inst().update_data(data);
}

void CTPTrader::on_market_status_update(const CThostFtdcInstrumentStatusField& status)
{
	/*if (is_stop()) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		init_status_.emplace_back(status);
		return;
	}

	if (status.InstrumentID[0]) {
		auto it = ctp_products_.find(status.InstrumentID);
		if (it != ctp_products_.end()) {
			CThostFtdcInstrumentStatusField& src_status = *it->second;
			src_status = status;
		}
		else {
			auto it = ctp_commoditys_.find(status.InstrumentID);
			if (it != ctp_commoditys_.end()) {
				CThostFtdcInstrumentStatusField& src_status = *it->second;
				src_status = status;
			}
		}
	}
	else {
		auto it = ctp_exchanges_.find(status.ExchangeID);
		if (it != ctp_exchanges_.end()) {
			CThostFtdcInstrumentStatusField& src_status = *it->second;
			src_status = status;
		}
	}

	MDMgr::Inst().update_status(status);*/
}

void CTPTrader::on_rsp_account(const std::shared_ptr<CTPAccountInfo>& account, bool is_last)
{
	if (is_stop()) {
		return;
	}

	on_init_account(account);
	if (is_last) {
		if (IsStateful(CTP_STAT_MAX)) {
			on_account_update();
		}
		on_init_done(CTP_STAT_TRADINGACCOUNT);
	}
}

void CTPTrader::on_rsp_order(const std::shared_ptr<CTPOrderInfo>& order, bool is_last)
{
	if (is_stop()) {
		return;
	}
	on_add_order(order);
	if (is_last) {
		on_init_done(CTP_STAT_ORDER);
	}
}

void CTPTrader::on_rsp_trade(const std::shared_ptr<CTPTradeInfo>& trade, bool is_last)
{
	if (is_stop()) {
		return;
	}
	on_add_trade(trade);
	if (is_last) {
		on_init_done(CTP_STAT_TRADE);
	}
}

void CTPTrader::on_rsp_position(const std::shared_ptr<CTPPositionInfo>& position, bool is_last)
{
	if (is_stop()) {
		return;
	}
	if (position) {
		if (!IsStateful(CTP_STAT_MAX)) {
			on_add_position(position);
		}
		else {
			on_position_update(position);
		}
	}
	if (is_last) {
		on_init_done(CTP_STAT_POSITION);
	}
}

void CTPTrader::on_account_update()
{
	if (is_stop()) {
		return;
	}
	//更新持仓信息
	user_->update_account(account_);
}

void CTPTrader::on_order_update(const std::shared_ptr<CTPOrderInfo>& order)
{
	if (is_stop()) {
		return;
	}
	if (!order)
		return;

	/*switch (order->OrderSubmitStatus)
	{
	case THOST_FTDC_OSS_InsertSubmitted:
	case THOST_FTDC_OSS_CancelSubmitted:
	case THOST_FTDC_OSS_ModifySubmitted: {
	return;
	} break;
	case THOST_FTDC_OSS_Accepted: {
	} break;
	case THOST_FTDC_OSS_InsertRejected:
	case THOST_FTDC_OSS_CancelRejected:
	case THOST_FTDC_OSS_ModifyRejected: {
	} break;
	}
	int errorid = 0;
	if (order->StatusMsg[0]) {
	errorid = -1;
	}*/

	do_response(order->RequestID, STR_MDB_FIELD_INDEX(ZQDB, ORDER, ORDER), order->id);
	orders_[order->id] = order;
	if (user_) {
		auto info = user_->update_order(order);
		reg_notify(info->hcode);
	}
}

void CTPTrader::on_trade_update(const std::shared_ptr<CTPTradeInfo>& trade)
{
	if (is_stop()) {
		return;
	}
	if (!trade)
		return;

	trades_[trade->id] = trade;
	if (user_) {
		auto info = user_->update_trade(trade);
		reg_notify(info->hcode);
	}
}

void CTPTrader::on_position_update(const std::shared_ptr<CTPPositionInfo>& position)
{
	if (is_stop()) {
		return;
	}
	if (!position->is_short()) {
		long_positions_[position->id] = position;
	}
	else {
		short_positions_[position->id] = position;
	}

	if (user_) {
		auto info = user_->update_position(position);
		reg_notify(info->hcode);
	}
	//更新完资金账号就会调用策略持仓更新
}

void CTPTrader::on_rsp_error()
{
	if (is_stop()) {
		return;
	}
	if (IsStateful(CTP_STAT_MAX)) {
		//继续刷新资金和持仓
		SetState({ CTP_STAT_TRADINGACCOUNT, CTP_STAT_POSITION }, false);
		SetInState({ CTP_STAT_TRADINGACCOUNT, CTP_STAT_POSITION }, false);
	}
	else {
		unregister_timer();
		register_timer_for_requery();
	}
}

void CTPTrader::on_rsp_order_send(const CThostFtdcInputOrderField& req, const CThostFtdcRspInfoField& rsp_info, int req_id)
{
	if (is_stop()) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		return;
	}

	auto errmsg = gbk_to_utf8(rsp_info.ErrorMsg);
	if (IsErrorRspInfo(&rsp_info)) {
		do_err_response(req.RequestID, rsp_info.ErrorID, errmsg.c_str());
	}
	LOG4I(STR_MODULE_NAME " %s OnRspOrderInsert %d %s", userid_.c_str(), rsp_info.ErrorID, errmsg.c_str());
}

void CTPTrader::on_rsp_order_cancel(const CThostFtdcInputOrderActionField& req, const CThostFtdcRspInfoField& rsp_info, int req_id)
{
	if (is_stop()) {
		return;
	}
	if (!IsStateful(CTP_STAT_MAX)) {
		return;
	}

	auto errmsg = gbk_to_utf8(rsp_info.ErrorMsg);
	if (IsErrorRspInfo(&rsp_info)) {
		do_err_response(req.RequestID, rsp_info.ErrorID, errmsg.c_str());
	}
	else {
		do_response(req.RequestID, STR_MDB_FIELD_INDEX(ZQDB, ORDER, ORDER), req.OrderSysID);
	}
	LOG4I(STR_MODULE_NAME " %s OnRspOrderAction %d %s", userid_.c_str(), rsp_info.ErrorID, errmsg.c_str());
}

void CTPTrader::on_err_order_send(const CThostFtdcInputOrderField& req) {
	if (is_stop()) {
		return;
	}
	//do_err_response(rsp_info, req.RequestID);
};

void CTPTrader::on_err_order_cancel(const CThostFtdcOrderActionField& req) {
	if (is_stop()) {
		return;
	}
	//do_err_response(rsp_info, req.RequestID);
};

void CTPTrader::on_rtn_order(const std::shared_ptr<CTPOrderInfo>& order) {
	if (is_stop()) {
		return;
	}
	if (IsStateful(CTP_STAT_MAX)) {
		on_order_update(order);
	}
	else {
		orders_[order->id] = order;
	}
};

void CTPTrader::on_rtn_trade(const std::shared_ptr<CTPTradeInfo>& trade) {
	if (is_stop()) {
		return;
	}
	if (IsStateful(CTP_STAT_MAX)) {
		on_trade_update(trade);
	}
	else {
		trades_[trade->id] = trade;
	}
};

//以下是来自交易回调

void CTPTrader::OnFrontConnected()
{
	service().post(boost::bind(&This::on_connect, shared_from_this()));
}

void CTPTrader::OnFrontDisconnected(int nReason)
{
	CTPTrader::service().post(boost::bind(&This::on_disconnect, shared_from_this()));
}

void CTPTrader::OnRspAuthenticate(CThostFtdcRspAuthenticateField *pRspAuthenticateField, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	CTPTrader::service().post(boost::bind(&This::on_authenticate, shared_from_this()
		, pRspAuthenticateField ? *pRspAuthenticateField : CThostFtdcRspAuthenticateField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_login, shared_from_this()
		, pRspUserLogin ? *pRspUserLogin : CThostFtdcRspUserLoginField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

///请求查询合约手续费率响应
void CTPTrader::OnRspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField *pInstrumentCommissionRate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	if (pInstrumentCommissionRate) {
		service().post(boost::bind(&This::on_add_commission_rate, shared_from_this(), *pInstrumentCommissionRate));
	}
	if (!pInstrumentCommissionRate || bIsLast) {
		service().post(boost::bind(&This::on_init_done, shared_from_this(), CTP_STAT_COMMISSIONRATE));
	}
};

///请求查询资金账户响应
void CTPTrader::OnRspQryTradingAccount(CThostFtdcTradingAccountField *pTradingAccount, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	service().post(boost::bind(&This::on_rsp_account, shared_from_this(), pTradingAccount ? std::make_shared<CTPAccountInfo>(*pTradingAccount) : nullptr
		, !pTradingAccount || bIsLast));
};

void CTPTrader::OnRspQrySettlementInfo(CThostFtdcSettlementInfoField *pSettlementInfo, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_add_settlement, shared_from_this()
		, pSettlementInfo ? *pSettlementInfo : CThostFtdcSettlementInfoField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_settlement_confirm, shared_from_this()
		, pSettlementInfoConfirm ? *pSettlementInfoConfirm : CThostFtdcSettlementInfoConfirmField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspQrySettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_add_settlement_confirm, shared_from_this()
		, pSettlementInfoConfirm ? *pSettlementInfoConfirm : CThostFtdcSettlementInfoConfirmField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspQryInvestor(CThostFtdcInvestorField *pInvestor, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_add_investor, shared_from_this()
		, pInvestor ? *pInvestor : CThostFtdcInvestorField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspQryTradingCode(CThostFtdcTradingCodeField *pTradingCode, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	service().post(boost::bind(&This::on_add_trading_code, shared_from_this()
		, pTradingCode ? *pTradingCode : CThostFtdcTradingCodeField{ 0 }
	, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, bIsLast));
}

void CTPTrader::OnRspUserPasswordUpdate(CThostFtdcUserPasswordUpdateField *pUserPasswordUpdate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{

}

void CTPTrader::OnRspTradingAccountPasswordUpdate(CThostFtdcTradingAccountPasswordUpdateField *pTradingAccountPasswordUpdate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{

}

void CTPTrader::OnRspQryExchange(CThostFtdcExchangeField *pExchange, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (pExchange) {
		service().post(boost::bind(&This::on_add_exchange, shared_from_this(), std::make_shared<CTPExchangeInfoEx>(*pExchange)));
	}
	if (!pExchange || bIsLast) {
		service().post(boost::bind(&This::on_init_done, shared_from_this(), CTP_STAT_EXCHANGE));
	}
}

void CTPTrader::OnRspQryProduct(CThostFtdcProductField *pProduct, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (pProduct) {
		if (pProduct->ProductClass == THOST_FTDC_PC_Futures) {
			service().post(boost::bind(&This::on_add_product, shared_from_this(), std::make_shared<CTPProductInfoEx>(*pProduct)));
		}
	}
	if (!pProduct || bIsLast)
	{
		service().post(boost::bind(&This::on_init_done, shared_from_this(), CTP_STAT_PRODUCT));
	}
}

void CTPTrader::OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (pInstrument) {
		if (pInstrument->ProductClass == THOST_FTDC_PC_Futures) {
			//只支持XX+YYMM和XX+YMM代码
			int ProductLen = strlen(pInstrument->ProductID);
			int InstrumentLen = strlen(pInstrument->InstrumentID);
			if (InstrumentLen <= ProductLen + 4) {
				auto ctp_commodity = std::make_shared<CTPCommodityInfoEx>(*pInstrument);
				if (strncmp(ctp_commodity->ProductID, ctp_commodity->Code, ProductLen))
				{
					//测试环境会出现代码和产品不一致情况，应该是交易所问题，这里容错一下
					strncpy(ctp_commodity->ProductID, ctp_commodity->Code, ProductLen);
				}
				service().post(boost::bind(&This::on_add_commodity, shared_from_this(), ctp_commodity));
			}
		}
	}
	if (!pInstrument || bIsLast) {
		service().post(boost::bind(&This::on_init_done, shared_from_this(), CTP_STAT_INSTRUMENT));
	}
}

void CTPTrader::OnRspQryDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
	if (pDepthMarketData) {
		service().post(boost::bind(&This::on_market_data_init, shared_from_this(), *pDepthMarketData));
	}
	if (!pDepthMarketData || bIsLast) {
		service().post(boost::bind(&This::on_init_done, shared_from_this(), CTP_STAT_DEPTHMARKETDATA));
	}
}

void CTPTrader::OnRtnInstrumentStatus(CThostFtdcInstrumentStatusField *pInstrumentStatus)
{
	if (pInstrumentStatus) {
		service().post(boost::bind(&This::on_market_status_update, shared_from_this(), *pInstrumentStatus));
	}
}

///请求查询报单响应
void CTPTrader::OnRspQryOrder(CThostFtdcOrderField *pOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	service().post(boost::bind(&This::on_rsp_order, shared_from_this(), pOrder ? std::make_shared<CTPOrderInfo>(*pOrder) : nullptr
		, !pOrder || bIsLast));
};

///请求查询成交响应
void CTPTrader::OnRspQryTrade(CThostFtdcTradeField *pTrade, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	service().post(boost::bind(&This::on_rsp_trade, shared_from_this(), pTrade ? std::make_shared<CTPTradeInfo>(*pTrade) : nullptr
		, !pTrade || bIsLast));
};

///请求查询投资者持仓响应
void CTPTrader::OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	service().post(boost::bind(&This::on_rsp_position, shared_from_this(), pInvestorPosition ? std::make_shared<CTPPositionInfo>(*pInvestorPosition) : nullptr
		, !pInvestorPosition || bIsLast));
};

///报单录入请求响应
void CTPTrader::OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	if (bIsLast) {
		service().post(boost::bind(&This::on_rsp_order_send, shared_from_this(), *pInputOrder, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, nRequestID));
	}
};

///报单操作请求响应
void CTPTrader::OnRspOrderAction(CThostFtdcInputOrderActionField *pInputOrderAction, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	if (bIsLast) {
		service().post(boost::bind(&This::on_rsp_order_cancel, shared_from_this(), *pInputOrderAction, pRspInfo ? *pRspInfo : CThostFtdcRspInfoField{ 0 }, nRequestID));
	}
};

///错误应答
void CTPTrader::OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	service().post(boost::bind(&This::on_rsp_error, shared_from_this()));
	if (IsErrorRspInfo(pRspInfo))
		LOG4I(STR_MODULE_NAME " %s OnRspError %d %s", userid_.c_str(), pRspInfo->ErrorID, gbk_to_utf8(pRspInfo->ErrorMsg).c_str());
};

///报单通知
void CTPTrader::OnRtnOrder(CThostFtdcOrderField *pOrder) {
	service().post(boost::bind(&This::on_rtn_order, shared_from_this(), pOrder ? std::make_shared<CTPOrderInfo>(*pOrder) : nullptr));
	//LOG4D("OnRtnOrder %s %s", pOrder->InstrumentID, pOrder->OrderSysID);
};

///成交通知
void CTPTrader::OnRtnTrade(CThostFtdcTradeField *pTrade) {
	service().post(boost::bind(&This::on_rtn_trade, shared_from_this(), pTrade ? std::make_shared<CTPTradeInfo>(*pTrade) : nullptr));
	//LOG4D("OnRtnTrade %s %s", pTrade->InstrumentID, pTrade->TradeID);
};

///报单录入错误回报
void CTPTrader::OnErrRtnOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo) {
	service().post(boost::bind(&This::on_err_order_send, shared_from_this(), *pInputOrder));
	if (IsErrorRspInfo(pRspInfo))
		LOG4I(STR_MODULE_NAME " %s OnErrRtnOrderInsert %d %s", userid_.c_str(), pRspInfo->ErrorID, gbk_to_utf8(pRspInfo->ErrorMsg).c_str());
};

///报单操作错误回报
void CTPTrader::OnErrRtnOrderAction(CThostFtdcOrderActionField *pOrderAction, CThostFtdcRspInfoField *pRspInfo) {
	service().post(boost::bind(&This::on_err_order_cancel, shared_from_this(), *pOrderAction));
	if (IsErrorRspInfo(pRspInfo))
		LOG4I(STR_MODULE_NAME " %s OnErrRtnOrderAction %d %s", userid_.c_str(), pRspInfo->ErrorID, gbk_to_utf8(pRspInfo->ErrorMsg).c_str());
};

void CTPTrader::OnRspQueryMaxOrderVolume(CThostFtdcQueryMaxOrderVolumeField *pQueryMaxOrderVolume, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{

}

///

TDMgr::TDMgr() : timer_(service())
{

}

void TDMgr::init()
{
	auto& cfg = Manager::Inst().cfg();
	MaxUserCount_ = cfg.get<size_t>("max_user", 10);
	MaxInvestorCount_ = cfg.get<size_t>("max_investor", 10);
	MaxAccountCount_ = cfg.get<size_t>("max_account", 10);
	MaxPositionCount_ = cfg.get<size_t>("max_position", 1000);
	MaxOrderCount_ = cfg.get<size_t>("max_order", 1000);
	MaxTradeCount_ = cfg.get<size_t>("max_trade", 1000);
}

bool TDMgr::start()
{
	//user表没有交易模块也要创建，模块新交易日初始化需要通过user表Enable/Disable
	auto htb_user = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_USER
		, MDB_FIELD_TABLE(CTP, USER), MDB_FIELD_TABLE_FIELD_COUNT(CTP, USER), MaxUserCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	users_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_USER, g_ctp_module);

	auto htb_investor = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_INVESTOR
		, MDB_FIELD_TABLE(CTP, INVESTOR), MDB_FIELD_TABLE_FIELD_COUNT(CTP, INVESTOR), MaxInvestorCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	investors_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_INVESTOR, g_ctp_module);

	auto htb_account = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_ACCOUNT
		, MDB_FIELD_TABLE(CTP, ACCOUNT), MDB_FIELD_TABLE_FIELD_COUNT(CTP, ACCOUNT), MaxAccountCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	accounts_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_ACCOUNT, g_ctp_module);

	auto htb_order = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_ORDER
		, MDB_FIELD_TABLE(ZQDB, ORDER), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, ORDER), MaxOrderCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	orders_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_ORDER, g_ctp_module);

	auto htb_trade = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_TRADE
		, MDB_FIELD_TABLE(ZQDB, TRADE), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, TRADE), MaxTradeCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	trades_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_TRADE, g_ctp_module);

	auto htb_position = ZQDBOpenOrInitTableEx(g_ctp_module, STR_ZQDB_TABLE_POSITION
		, MDB_FIELD_TABLE(ZQDB, POSITION), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, POSITION), MaxPositionCount_, ZQDB_OPEN_TABLE_FLAG_SYNC_DATA | MDB_OPEN_FLAG_TEMP);
	positions_ = std::make_shared<zqdb::AllTableData>(STR_ZQDB_TABLE_POSITION, g_ctp_module);

	htb_commission_rate_ = ZQDBOpenOrInitTableEx(g_ctp_module, STR_CTP_TABLE_COMMISSIONRATE
		, MDB_FIELD_TABLE(CTP, COMMISSIONRATE), MDB_FIELD_TABLE_FIELD_COUNT(CTP, COMMISSIONRATE), MaxProductCountPerExchange * 10, MDB_OPEN_FLAG_TEMP);

	Base::start();

	return true;
}

void TDMgr::run()
{
	if (ZQDBIsTest()) {
		//启动时自己normal，
		//后面通过begin/init/end_newtradingday完成交易日切换，
		//实盘也是通过begin/init/end_newtradingday完成交易日切换。
		service().post(boost::bind(&TDMgr::on_normal, this, false));
	}
	else {
		auto& cfg = Manager::Inst().cfg();
		auto opt_user = cfg.get_child_optional("user");
		if (opt_user)
		{
			const boost::property_tree::ptree &cfg_user = opt_user.get();
			BOOST_FOREACH(const boost::property_tree::ptree::value_type &cfgi, cfg_user)
			{
				const auto& cfg_one = cfgi.second;
				std::string user = cfg_one.get<std::string>("UserID", "");
				auto trader = std::make_shared<CTPTrader>(traders_.empty(), service());
				if (trader->start((char*)&cfg_one, XUtil::XML_FLAG_PTREE)) {
					add_trader(user, trader);
				}
			}
		}
		if (MDMgr::Inst().is_markets_empty()) {

		}
		else {
			ASSERT(!traders_.empty());
			//trader会触发on_normal
		}
	}
}

void TDMgr::stop()
{
	stop_flag_ = true;

	unregister_timer();

	{
		std::unique_lock<std::mutex> lock(mutex_);
		auto traders = traders_;
		lock.unlock();
		for (auto& pr : traders)
		{
			pr.second->stop();
		}
	}

	Base::stop();

	{
		std::unique_lock<std::mutex> lock(mutex_);
		traders_.clear();
	}
}

void TDMgr::unregister_timer()
{
	LOG4I(STR_MODULE_NAME " TDMgr::unregister_timer");
	boost::system::error_code ec;
	timer_.cancel(ec);
}

void TDMgr::on_normal(bool new_trading_day)
{
	if (normal_flag_) {
		return;
	}
	normal_flag_ = true;
}

void TDMgr::HandleNotify(HZQDB h, ZQDB_NOTIFY_TYPE notify)
{
	switch (h->type)
	{
	case ZQDB_HANDLE_TYPE_CODE: {

	} break;
	default: {
		return;
	} break;
	}
	std::unique_lock<std::mutex> lock(mutex_);
	for (auto& pr : traders_)
	{
		pr.second->HandleNotify(h, notify);
	}
}

int TDMgr::request(zqdb::Msg& msg)
{
	if (is_stop()) {
		return ZQDB_STATUS_ERROR;
	}
	if (!normal_flag_) {
		return ZQDB_STATUS_ERROR;
	}
	switch (msg.GetMsgType())
	{
	case ZQDB_MSG_REQUEST_DO: {
		auto req_type = msg.GetReqType();
		switch (req_type)
		{
		case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_USER_LOGIN: {
			auto Broker = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), "");
			auto User = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), "");
			auto trader = find_trader(User);
			if (trader) {
				trader->update(msg);
				zqdb::Msg rsp(ZQDB_MSG_RESPONSE);
				rsp.SetNode(msg.GetNode());
				rsp.SetBizType(msg.GetBizType());
				rsp.SetID(msg.GetID());
				rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), Broker);
				rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), User);
				rsp.SetError(ZQDB_STATUS_IN_USE, u8"交易账户已存在，不能重复登录");
				ZQDBSendMsg(rsp);
			}
			else {
				auto trader = std::make_shared<CTPTrader>(false, service());
				if (trader->start(msg)) {
					add_trader(User, trader);
				}
				else {
					zqdb::Msg rsp(ZQDB_MSG_RESPONSE);
					rsp.SetNode(msg.GetNode());
					rsp.SetBizType(msg.GetBizType());
					rsp.SetID(msg.GetID());
					rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), Broker);
					rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), User);
					rsp.SetError(ZQDB_STATUS_INVALID_PARAM, u8"创建交易对象失败，账号信息有误");
					ZQDBSendMsg(rsp);
				}
			}
			return ZQDB_STATUS_OK;
		} break;
		case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_USER_LOGOUT: {
			auto Broker = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), "");
			auto User = msg.GetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), "");
			zqdb::Msg rsp(ZQDB_MSG_RESPONSE);
			rsp.SetNode(msg.GetNode());
			rsp.SetBizType(msg.GetBizType());
			rsp.SetID(msg.GetID());
			rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, BROKER), Broker);
			rsp.SetParam(STR_MDB_FIELD_INDEX(CTP, USER, USER), User);
			std::shared_ptr<CTPTrader>* trader = nullptr;
			if (remove_trader(User, trader)) {
				rsp.SetError(0, u8"");
			}
			else {
				if (trader) {
					rsp.SetError(ZQDB_STATUS_NOT_EXIST, u8"交易账户不可删除");
				}
				else {
					rsp.SetError(ZQDB_STATUS_NOT_EXIST, u8"交易账户不存在");
				}
			}
			ZQDBSendMsg(rsp);
			return ZQDB_STATUS_OK;
		} break;
		default: {
			auto trader = find_trader(msg.GetParam(STR_MDB_FIELD_INDEX(ZQDB, USER, USER), ""));
			if (!trader) {
				break;
			}
			return trader->request(msg);
		} break;
		}
	} break;
	}
	return ZQDB_STATUS_ERROR;
}

std::shared_ptr<CTPTrader> TDMgr::find_trader(const std::string& user)
{
	std::unique_lock<std::mutex> lock(mutex_);
	auto it = traders_.find(user);
	if (it != traders_.end()) {
		return it->second;
	}
	return nullptr;
}

void TDMgr::add_trader(const std::string& user, std::shared_ptr<CTPTrader> trader)
{
	std::unique_lock<std::mutex> lock(mutex_);
	traders_[user] = trader;
}

bool TDMgr::remove_trader(const std::string& user, std::shared_ptr<CTPTrader>* trader)
{
	std::unique_lock<std::mutex> lock(mutex_);
	auto it = traders_.find(user);
	if (it != traders_.end()) {
		if (trader) {
			*trader = it->second;
		}
		if (!it->second->is_removable()) {
			return false;
		}
		it->second->stop();
		traders_.erase(it);
		return true;
	}
	return false;
}

HZQDB TDMgr::find_trader(tagCTPUserInfo* user)
{
	std::unique_lock<std::mutex> lock(mutex_);
	for (auto h : *users_)
	{
		auto data = (tagCTPUserInfo*)ZQDBGetValue(h);
		if (strcmp(data->User, user->User) == 0 && strcmp(data->Broker, user->Broker) == 0) {
			return h;
			break;
		}
	}
	return nullptr;
}

HZQDB TDMgr::update_user(HZQDB h, tagCTPUserInfo* user)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, USER), MDB_FIELD_TABLE_FIELD_COUNT(CTP, USER), user);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			for (auto h : *users_)
			{
				auto data = (tagCTPUserInfo*)ZQDBGetValue(h);
				if (strcmp(data->User, user->User) == 0 && strcmp(data->Broker, user->Broker) == 0) {
					lock.unlock();
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, USER), MDB_FIELD_TABLE_FIELD_COUNT(CTP, USER), user);
					return h;
					break;
				}
			}
		}
		//strcpy(trade->User, user->data->User);
		//strcpy(trade->Broker, user->data->Broker);
		h = ZQDBAddAndGetTableData(*users_, user);
		users_->emplace_back(h);
		return h;
	}
	return nullptr;
}

HZQDB TDMgr::update_investor(HZQDB h, tagCTPInvestorInfo* investor)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, INVESTOR), MDB_FIELD_TABLE_FIELD_COUNT(CTP, INVESTOR), investor);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			for (auto h : *investors_)
			{
				auto data = (tagCTPInvestorInfo*)ZQDBGetValue(h);
				if (strcmp(data->Investor, investor->Investor) == 0 && strcmp(data->User, investor->User) == 0 && strcmp(data->Broker, investor->Broker) == 0) {
					lock.unlock();
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, INVESTOR), MDB_FIELD_TABLE_FIELD_COUNT(CTP, INVESTOR), investor);
					return h;
					break;
				}
			}
		}
		//strcpy(trade->User, user->data->User);
		//strcpy(trade->Broker, user->data->Broker);
		h = ZQDBAddAndGetTableData(*investors_, investor);
		investors_->emplace_back(h);
		return h;
	}
	return nullptr;
}

HZQDB TDMgr::update_account(HZQDB h, tagCTPAccountInfo* account)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, ACCOUNT), MDB_FIELD_TABLE_FIELD_COUNT(CTP, ACCOUNT), account);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			for (auto h : *accounts_)
			{
				auto data = (tagCTPAccountInfo*)ZQDBGetValue(h);
				if (strcmp(data->Account, account->Account) == 0 && strcmp(data->User, account->User) == 0 && strcmp(data->Broker, account->Broker) == 0) {
					lock.unlock();
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(CTP, ACCOUNT), MDB_FIELD_TABLE_FIELD_COUNT(CTP, ACCOUNT), account);
					return h;
					break;
				}
			}
		}
		//strcpy(trade->User, user->data->User);
		//strcpy(trade->Broker, user->data->Broker);
		h = ZQDBAddAndGetTableData(*accounts_, account);
		accounts_->emplace_back(h);
		return h;
	}
	return nullptr;
}

HZQDB TDMgr::update_order(HZQDB h, tagOrderInfo* order)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, ORDER), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, ORDER), order);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			orders_->Update();
			for (auto h : *orders_)
			{
				auto data = (tagOrderInfo*)ZQDBGetValue(h);
				if (strcmp(data->Order, order->Order) == 0) {
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, ORDER), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, ORDER), order);
					return h;
					break;
				}
			}
		}
		//strcpy(order->User, user->data->User);
		//strcpy(order->Broker, user->data->Broker);
		return ZQDBAddAndGetTableData(*orders_, order);
	}
	return nullptr;
}

HZQDB TDMgr::update_trade(HZQDB h, tagTradeInfo* trade)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, TRADE), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, TRADE), trade);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			for (auto h : *trades_)
			{
				auto data = (tagTradeInfo*)ZQDBGetValue(h);
				if (strcmp(data->Trade, trade->Trade) == 0) {
					lock.unlock();
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, TRADE), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, TRADE), trade);
					return h;
					break;
				}
			}
		}
		//strcpy(trade->User, user->data->User);
		//strcpy(trade->Broker, user->data->Broker);
		h = ZQDBAddAndGetTableData(*trades_, trade);
		trades_->emplace_back(h);
		return h;
	}
	return nullptr;
}

HZQDB TDMgr::update_position(HZQDB h, tagPositionInfo* position)
{
	if (h) {
		ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, POSITION), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, POSITION), position);
		return h;
	}
	else {
		{
			std::unique_lock<std::mutex> lock(mutex_);
			for (auto h : *positions_)
			{
				auto data = (tagPositionInfo*)ZQDBGetValue(h);
				if (strcmp(data->Code, position->Code) == 0
					&& data->Direction == position->Direction) {
					lock.unlock();
					ZQDBUpdateTableDataFieldValue(h, MDB_FIELD_TABLE(ZQDB, POSITION), MDB_FIELD_TABLE_FIELD_COUNT(ZQDB, POSITION), position);
					return h;
					break;
				}
			}
		}
		//strcpy(position->User, user->data->User);
		//strcpy(position->Broker, user->data->Broker);
		h = ZQDBAddAndGetTableData(*positions_, position);
		positions_->emplace_back(h);
		return h;
	}
	return nullptr;
}

void TDMgr::begin_new_tradingday(std::promise<int>* promise)
{
	normal_flag_ = false;
	
	promise->set_value(0);
}

void TDMgr::begin_new_tradingday()
{
	std::promise<int> promise;
	service().post(boost::bind(&This::begin_new_tradingday, this, &promise));
	auto val = promise.get_future().get();
}

void TDMgr::clear_new_tradingday(std::promise<int>* promise)
{
	//清理trader对象
	for (auto& pr : traders_)
	{
		pr.second->on_clear_new_tradingday();
	}
	//清理db
	positions_->clear();
	trades_->clear();
	orders_->clear();
	accounts_->clear();
	investors_->clear();
	users_->clear();
	ZQDBClearTableData(*positions_);
	ZQDBClearTableData(*trades_);
	ZQDBClearTableData(*orders_);
	ZQDBClearTableData(*accounts_);
	ZQDBClearTableData(*investors_);
	ZQDBClearTableData(*users_);
	//
	ZQDBRemoveTableDataValue(htb_commission_rate_, 0, (size_t)-1);
	
	promise->set_value(0);
}

void TDMgr::clear_new_tradingday()
{
	std::promise<int> promise;
	service().post(boost::bind(&This::clear_new_tradingday, this, &promise));
	auto val = promise.get_future().get();
}

void TDMgr::init_new_tradingday(std::promise<int>* promise)
{
	/*if (!ZQDBGetTableDataCount(htb_commission_rate_)) {
		//没有数据，则需要写入数据
		for (auto& pr : trader->ctp_products_)
		{
			auto& product = pr.second;
			tagCommissionRateInfo info = { 0 };
			strcpy(info.Broker, trader->user_->Broker);
			strcpy(info.User, trader->user_->User);
			strcpy(info.Investor, product->InvestorID);
			strcpy(info.InstrumentID, product->Product);
			info.InvestorRange = product->InvestorRange;
			info.OpenRatioByMoney = product->OpenRatioByMoney;
			info.OpenRatioByVolume = product->OpenRatioByVolume;
			info.CloseRatioByMoney = product->CloseRatioByMoney;
			info.CloseRatioByVolume = product->CloseRatioByVolume;
			info.CloseTodayRatioByMoney = product->CloseTodayRatioByMoney;
			info.CloseTodayRatioByVolume = product->CloseTodayRatioByVolume;
			strcpy(info.ExchangeID, product->Exchange);
			info.BizType = product->BizType;
			strcpy(info.InvestUnitID, product->InvestUnitID);
			ZQDBAddTableDataValue(htb_commission_rate_, &info);
		}
	}*/

	for (auto& pr : traders_)
	{
		pr.second->on_init_new_tradingday();
	}

	promise->set_value(0);
}

void TDMgr::init_new_tradingday()
{
	std::promise<int> promise;
	service().post(boost::bind(&This::init_new_tradingday, this, &promise));
	auto val = promise.get_future().get();
}

void TDMgr::end_new_tradingday(std::promise<int>* promise)
{
	for (auto& pr : traders_)
	{
		pr.second->on_end_new_tradingday();
	}
	on_normal(true);

	promise->set_value(0);
}

void TDMgr::end_new_tradingday()
{
	std::promise<int> promise;
	service().post(boost::bind(&This::end_new_tradingday, this, &promise));
	auto val = promise.get_future().get();
}
